]> git.saurik.com Git - apple/ld64.git/blob - ld64-134.9/src/ld/LinkEdit.hpp
c45e34fc75525909eda9ad08520d70ff58365de3
[apple/ld64.git] / ld64-134.9 / src / ld / LinkEdit.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 *
3 * Copyright (c) 2009-2010 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 #ifndef __LINKEDIT_HPP__
26 #define __LINKEDIT_HPP__
27
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <unistd.h>
33
34 #include <vector>
35
36 #include "Options.h"
37 #include "ld.hpp"
38 #include "Architectures.hpp"
39 #include "MachOFileAbstraction.hpp"
40 #include "code-sign-blobs/superblob.h"
41
42 namespace ld {
43 namespace tool {
44
45 class ByteStream {
46 private:
47 std::vector<uint8_t> _data;
48 public:
49 std::vector<uint8_t>& bytes() { return _data; }
50 unsigned long size() const { return _data.size(); }
51 void reserve(unsigned long l) { _data.reserve(l); }
52 const uint8_t* start() const { return &_data[0]; }
53
54 void append_uleb128(uint64_t value) {
55 uint8_t byte;
56 do {
57 byte = value & 0x7F;
58 value &= ~0x7F;
59 if ( value != 0 )
60 byte |= 0x80;
61 _data.push_back(byte);
62 value = value >> 7;
63 } while( byte >= 0x80 );
64 }
65
66 void append_sleb128(int64_t value) {
67 bool isNeg = ( value < 0 );
68 uint8_t byte;
69 bool more;
70 do {
71 byte = value & 0x7F;
72 value = value >> 7;
73 if ( isNeg )
74 more = ( (value != -1) || ((byte & 0x40) == 0) );
75 else
76 more = ( (value != 0) || ((byte & 0x40) != 0) );
77 if ( more )
78 byte |= 0x80;
79 _data.push_back(byte);
80 }
81 while( more );
82 }
83
84 void append_string(const char* str) {
85 for (const char* s = str; *s != '\0'; ++s)
86 _data.push_back(*s);
87 _data.push_back('\0');
88 }
89
90 void append_byte(uint8_t byte) {
91 _data.push_back(byte);
92 }
93
94 static unsigned int uleb128_size(uint64_t value) {
95 uint32_t result = 0;
96 do {
97 value = value >> 7;
98 ++result;
99 } while ( value != 0 );
100 return result;
101 }
102
103 void pad_to_size(unsigned int alignment) {
104 while ( (_data.size() % alignment) != 0 )
105 _data.push_back(0);
106 }
107 };
108
109
110 class LinkEditAtom : public ld::Atom
111 {
112 public:
113
114 // overrides of ld::Atom
115 virtual ld::File* file() const { return NULL; }
116 virtual uint64_t objectAddress() const { return 0; }
117 virtual uint64_t size() const;
118 virtual void copyRawContent(uint8_t buffer[]) const;
119
120 virtual void encode() const = 0;
121
122 LinkEditAtom(const Options& opts, ld::Internal& state,
123 OutputFile& writer, const ld::Section& sect,
124 unsigned int pointerSize)
125 : ld::Atom(sect, ld::Atom::definitionRegular,
126 ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
127 ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
128 false, false, false, ld::Atom::Alignment(log2(pointerSize))),
129 _options(opts), _state(state), _writer(writer),
130 _encoded(false) { }
131 protected:
132 const Options& _options;
133 ld::Internal& _state;
134 OutputFile& _writer;
135 mutable ByteStream _encodedData;
136 mutable bool _encoded;
137 };
138
139 uint64_t LinkEditAtom::size() const
140 {
141 assert(_encoded);
142 return _encodedData.size();
143 }
144
145 void LinkEditAtom::copyRawContent(uint8_t buffer[]) const
146 {
147 assert(_encoded);
148 memcpy(buffer, _encodedData.start(), _encodedData.size());
149 }
150
151
152
153
154 template <typename A>
155 class RebaseInfoAtom : public LinkEditAtom
156 {
157 public:
158 RebaseInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
159 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
160
161 // overrides of ld::Atom
162 virtual const char* name() const { return "rebase info"; }
163 // overrides of LinkEditAtom
164 virtual void encode() const;
165
166 private:
167 struct rebase_tmp
168 {
169 rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
170 uint8_t opcode;
171 uint64_t operand1;
172 uint64_t operand2;
173 };
174
175 typedef typename A::P P;
176 typedef typename A::P::E E;
177 typedef typename A::P::uint_t pint_t;
178
179 static ld::Section _s_section;
180 };
181
182 template <typename A>
183 ld::Section RebaseInfoAtom<A>::_s_section("__LINKEDIT", "__rebase", ld::Section::typeLinkEdit, true);
184
185
186 template <typename A>
187 void RebaseInfoAtom<A>::encode() const
188 {
189 // omit relocs if this was supposed to be PIE but PIE not possible
190 if ( _options.positionIndependentExecutable() && this->_writer.pieDisabled )
191 return;
192
193 // sort rebase info by type, then address
194 std::vector<OutputFile::RebaseInfo>& info = this->_writer._rebaseInfo;
195 std::sort(info.begin(), info.end());
196
197 // convert to temp encoding that can be more easily optimized
198 std::vector<rebase_tmp> mid;
199 uint64_t curSegStart = 0;
200 uint64_t curSegEnd = 0;
201 uint32_t curSegIndex = 0;
202 uint8_t type = 0;
203 uint64_t address = (uint64_t)(-1);
204 for (std::vector<OutputFile::RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
205 if ( type != it->_type ) {
206 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->_type));
207 type = it->_type;
208 }
209 if ( address != it->_address ) {
210 if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
211 if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
212 throw "binding address outside range of any segment";
213 mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
214 }
215 else {
216 mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->_address-address));
217 }
218 address = it->_address;
219 }
220 mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
221 address += sizeof(pint_t);
222 }
223 mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
224
225 // optimize phase 1, compress packed runs of pointers
226 rebase_tmp* dst = &mid[0];
227 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
228 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
229 *dst = *src++;
230 while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
231 dst->operand1 += src->operand1;
232 ++src;
233 }
234 --src;
235 ++dst;
236 }
237 else {
238 *dst++ = *src;
239 }
240 }
241 dst->opcode = REBASE_OPCODE_DONE;
242
243 // optimize phase 2, combine rebase/add pairs
244 dst = &mid[0];
245 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
246 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
247 && (src->operand1 == 1)
248 && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
249 dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
250 dst->operand1 = src[1].operand1;
251 ++src;
252 ++dst;
253 }
254 else {
255 *dst++ = *src;
256 }
257 }
258 dst->opcode = REBASE_OPCODE_DONE;
259
260 // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
261 // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
262 dst = &mid[0];
263 for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
264 uint64_t delta = src->operand1;
265 if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
266 && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
267 && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
268 && (src[1].operand1 == delta)
269 && (src[2].operand1 == delta) ) {
270 // found at least three in a row, this is worth compressing
271 dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
272 dst->operand1 = 1;
273 dst->operand2 = delta;
274 ++src;
275 while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
276 && (src->operand1 == delta) ) {
277 dst->operand1++;
278 ++src;
279 }
280 --src;
281 ++dst;
282 }
283 else {
284 *dst++ = *src;
285 }
286 }
287 dst->opcode = REBASE_OPCODE_DONE;
288
289 // optimize phase 4, use immediate encodings
290 for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
291 if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB)
292 && (p->operand1 < (15*sizeof(pint_t)))
293 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
294 p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
295 p->operand1 = p->operand1/sizeof(pint_t);
296 }
297 else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
298 p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
299 }
300 }
301
302 // convert to compressed encoding
303 const static bool log = false;
304 this->_encodedData.reserve(info.size()*2);
305 bool done = false;
306 for (typename std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
307 switch ( it->opcode ) {
308 case REBASE_OPCODE_DONE:
309 if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
310 done = true;
311 break;
312 case REBASE_OPCODE_SET_TYPE_IMM:
313 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
314 this->_encodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
315 break;
316 case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
317 if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
318 this->_encodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
319 this->_encodedData.append_uleb128(it->operand2);
320 break;
321 case REBASE_OPCODE_ADD_ADDR_ULEB:
322 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
323 this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
324 this->_encodedData.append_uleb128(it->operand1);
325 break;
326 case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
327 if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
328 this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
329 break;
330 case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
331 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
332 this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
333 break;
334 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
335 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
336 this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
337 this->_encodedData.append_uleb128(it->operand1);
338 break;
339 case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
340 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
341 this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
342 this->_encodedData.append_uleb128(it->operand1);
343 break;
344 case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
345 if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
346 this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
347 this->_encodedData.append_uleb128(it->operand1);
348 this->_encodedData.append_uleb128(it->operand2);
349 break;
350 }
351 }
352
353
354 // align to pointer size
355 this->_encodedData.pad_to_size(sizeof(pint_t));
356
357 this->_encoded = true;
358
359 if (log) fprintf(stderr, "total rebase info size = %ld\n", this->_encodedData.size());
360 }
361
362
363 template <typename A>
364 class BindingInfoAtom : public LinkEditAtom
365 {
366 public:
367 BindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
368 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
369
370 // overrides of ld::Atom
371 virtual const char* name() const { return "binding info"; }
372 // overrides of LinkEditAtom
373 virtual void encode() const;
374
375
376 private:
377 typedef typename A::P P;
378 typedef typename A::P::E E;
379 typedef typename A::P::uint_t pint_t;
380
381 struct binding_tmp
382 {
383 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
384 : opcode(op), operand1(p1), operand2(p2), name(s) {}
385 uint8_t opcode;
386 uint64_t operand1;
387 uint64_t operand2;
388 const char* name;
389 };
390
391 static ld::Section _s_section;
392 };
393
394 template <typename A>
395 ld::Section BindingInfoAtom<A>::_s_section("__LINKEDIT", "__binding", ld::Section::typeLinkEdit, true);
396
397
398 template <typename A>
399 void BindingInfoAtom<A>::encode() const
400 {
401 // sort by library, symbol, type, then address
402 std::vector<OutputFile::BindingInfo>& info = this->_writer._bindingInfo;
403 std::sort(info.begin(), info.end());
404
405 // convert to temp encoding that can be more easily optimized
406 std::vector<binding_tmp> mid;
407 uint64_t curSegStart = 0;
408 uint64_t curSegEnd = 0;
409 uint32_t curSegIndex = 0;
410 int ordinal = 0x80000000;
411 const char* symbolName = NULL;
412 uint8_t type = 0;
413 uint64_t address = (uint64_t)(-1);
414 int64_t addend = 0;
415 for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
416 if ( ordinal != it->_libraryOrdinal ) {
417 if ( it->_libraryOrdinal <= 0 ) {
418 // special lookups are encoded as negative numbers in BindingInfo
419 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->_libraryOrdinal));
420 }
421 else {
422 mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->_libraryOrdinal));
423 }
424 ordinal = it->_libraryOrdinal;
425 }
426 if ( symbolName != it->_symbolName ) {
427 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
428 symbolName = it->_symbolName;
429 }
430 if ( type != it->_type ) {
431 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
432 type = it->_type;
433 }
434 if ( address != it->_address ) {
435 if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
436 if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
437 throw "binding address outside range of any segment";
438 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
439 }
440 else {
441 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
442 }
443 address = it->_address;
444 }
445 if ( addend != it->_addend ) {
446 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
447 addend = it->_addend;
448 }
449 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
450 address += sizeof(pint_t);
451 }
452 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
453
454
455 // optimize phase 1, combine bind/add pairs
456 binding_tmp* dst = &mid[0];
457 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
458 if ( (src->opcode == BIND_OPCODE_DO_BIND)
459 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
460 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
461 dst->operand1 = src[1].operand1;
462 ++src;
463 ++dst;
464 }
465 else {
466 *dst++ = *src;
467 }
468 }
469 dst->opcode = BIND_OPCODE_DONE;
470
471 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
472 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
473 dst = &mid[0];
474 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
475 uint64_t delta = src->operand1;
476 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
477 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
478 && (src[1].operand1 == delta) ) {
479 // found at least two in a row, this is worth compressing
480 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
481 dst->operand1 = 1;
482 dst->operand2 = delta;
483 ++src;
484 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
485 && (src->operand1 == delta) ) {
486 dst->operand1++;
487 ++src;
488 }
489 --src;
490 ++dst;
491 }
492 else {
493 *dst++ = *src;
494 }
495 }
496 dst->opcode = BIND_OPCODE_DONE;
497
498 // optimize phase 3, use immediate encodings
499 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
500 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
501 && (p->operand1 < (15*sizeof(pint_t)))
502 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
503 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
504 p->operand1 = p->operand1/sizeof(pint_t);
505 }
506 else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
507 p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
508 }
509 }
510 dst->opcode = BIND_OPCODE_DONE;
511
512 // convert to compressed encoding
513 const static bool log = false;
514 this->_encodedData.reserve(info.size()*2);
515 bool done = false;
516 for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
517 switch ( it->opcode ) {
518 case BIND_OPCODE_DONE:
519 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
520 done = true;
521 break;
522 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
523 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
524 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
525 break;
526 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
527 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
528 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
529 this->_encodedData.append_uleb128(it->operand1);
530 break;
531 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
532 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
533 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
534 break;
535 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
536 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
537 this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
538 this->_encodedData.append_string(it->name);
539 break;
540 case BIND_OPCODE_SET_TYPE_IMM:
541 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
542 this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
543 break;
544 case BIND_OPCODE_SET_ADDEND_SLEB:
545 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
546 this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
547 this->_encodedData.append_sleb128(it->operand1);
548 break;
549 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
550 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
551 this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
552 this->_encodedData.append_uleb128(it->operand2);
553 break;
554 case BIND_OPCODE_ADD_ADDR_ULEB:
555 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
556 this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
557 this->_encodedData.append_uleb128(it->operand1);
558 break;
559 case BIND_OPCODE_DO_BIND:
560 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
561 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
562 break;
563 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
564 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
565 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
566 this->_encodedData.append_uleb128(it->operand1);
567 break;
568 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
569 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
570 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
571 break;
572 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
573 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
574 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
575 this->_encodedData.append_uleb128(it->operand1);
576 this->_encodedData.append_uleb128(it->operand2);
577 break;
578 }
579 }
580
581 // align to pointer size
582 this->_encodedData.pad_to_size(sizeof(pint_t));
583
584 this->_encoded = true;
585
586 if (log) fprintf(stderr, "total binding info size = %ld\n", this->_encodedData.size());
587 }
588
589
590
591 template <typename A>
592 class WeakBindingInfoAtom : public LinkEditAtom
593 {
594 public:
595 WeakBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
596 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
597
598 // overrides of ld::Atom
599 virtual const char* name() const { return "weak binding info"; }
600 // overrides of LinkEditAtom
601 virtual void encode() const;
602
603 private:
604 typedef typename A::P P;
605 typedef typename A::P::E E;
606 typedef typename A::P::uint_t pint_t;
607
608 struct WeakBindingSorter
609 {
610 bool operator()(const OutputFile::BindingInfo& left, const OutputFile::BindingInfo& right)
611 {
612 // sort by symbol, type, address
613 if ( left._symbolName != right._symbolName )
614 return ( strcmp(left._symbolName, right._symbolName) < 0 );
615 if ( left._type != right._type )
616 return (left._type < right._type);
617 return (left._address < right._address);
618 }
619 };
620
621 struct binding_tmp
622 {
623 binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL)
624 : opcode(op), operand1(p1), operand2(p2), name(s) {}
625 uint8_t opcode;
626 uint64_t operand1;
627 uint64_t operand2;
628 const char* name;
629 };
630
631 static ld::Section _s_section;
632 };
633
634 template <typename A>
635 ld::Section WeakBindingInfoAtom<A>::_s_section("__LINKEDIT", "__weak_binding", ld::Section::typeLinkEdit, true);
636
637
638 template <typename A>
639 void WeakBindingInfoAtom<A>::encode() const
640 {
641 // sort by symbol, type, address
642 std::vector<OutputFile::BindingInfo>& info = this->_writer._weakBindingInfo;
643 if ( info.size() == 0 ) {
644 // short circuit if no weak binding needed
645 this->_encoded = true;
646 return;
647 }
648 std::sort(info.begin(), info.end(), WeakBindingSorter());
649
650 // convert to temp encoding that can be more easily optimized
651 std::vector<binding_tmp> mid;
652 mid.reserve(info.size());
653 uint64_t curSegStart = 0;
654 uint64_t curSegEnd = 0;
655 uint32_t curSegIndex = 0;
656 const char* symbolName = NULL;
657 uint8_t type = 0;
658 uint64_t address = (uint64_t)(-1);
659 int64_t addend = 0;
660 for (typename std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
661 if ( symbolName != it->_symbolName ) {
662 mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
663 symbolName = it->_symbolName;
664 }
665 // non-weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
666 // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
667 if ( it->_type != BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB ) {
668 if ( type != it->_type ) {
669 mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
670 type = it->_type;
671 }
672 if ( address != it->_address ) {
673 if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
674 if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
675 throw "binding address outside range of any segment";
676 mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
677 }
678 else {
679 mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
680 }
681 address = it->_address;
682 }
683 if ( addend != it->_addend ) {
684 mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
685 addend = it->_addend;
686 }
687 mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
688 address += sizeof(pint_t);
689 }
690 }
691 mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
692
693
694 // optimize phase 1, combine bind/add pairs
695 binding_tmp* dst = &mid[0];
696 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
697 if ( (src->opcode == BIND_OPCODE_DO_BIND)
698 && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
699 dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
700 dst->operand1 = src[1].operand1;
701 ++src;
702 ++dst;
703 }
704 else {
705 *dst++ = *src;
706 }
707 }
708 dst->opcode = BIND_OPCODE_DONE;
709
710 // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
711 // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
712 dst = &mid[0];
713 for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
714 uint64_t delta = src->operand1;
715 if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
716 && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
717 && (src[1].operand1 == delta) ) {
718 // found at least two in a row, this is worth compressing
719 dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
720 dst->operand1 = 1;
721 dst->operand2 = delta;
722 ++src;
723 while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
724 && (src->operand1 == delta) ) {
725 dst->operand1++;
726 ++src;
727 }
728 --src;
729 ++dst;
730 }
731 else {
732 *dst++ = *src;
733 }
734 }
735 dst->opcode = BIND_OPCODE_DONE;
736
737 // optimize phase 3, use immediate encodings
738 for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
739 if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
740 && (p->operand1 < (15*sizeof(pint_t)))
741 && ((p->operand1 % sizeof(pint_t)) == 0) ) {
742 p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
743 p->operand1 = p->operand1/sizeof(pint_t);
744 }
745 }
746 dst->opcode = BIND_OPCODE_DONE;
747
748
749 // convert to compressed encoding
750 const static bool log = false;
751 this->_encodedData.reserve(info.size()*2);
752 bool done = false;
753 for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
754 switch ( it->opcode ) {
755 case BIND_OPCODE_DONE:
756 if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
757 this->_encodedData.append_byte(BIND_OPCODE_DONE);
758 done = true;
759 break;
760 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
761 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
762 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
763 break;
764 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
765 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
766 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
767 this->_encodedData.append_uleb128(it->operand1);
768 break;
769 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
770 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
771 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
772 break;
773 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
774 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
775 this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
776 this->_encodedData.append_string(it->name);
777 break;
778 case BIND_OPCODE_SET_TYPE_IMM:
779 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
780 this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
781 break;
782 case BIND_OPCODE_SET_ADDEND_SLEB:
783 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
784 this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
785 this->_encodedData.append_sleb128(it->operand1);
786 break;
787 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
788 if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
789 this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
790 this->_encodedData.append_uleb128(it->operand2);
791 break;
792 case BIND_OPCODE_ADD_ADDR_ULEB:
793 if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
794 this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
795 this->_encodedData.append_uleb128(it->operand1);
796 break;
797 case BIND_OPCODE_DO_BIND:
798 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
799 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
800 break;
801 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
802 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
803 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
804 this->_encodedData.append_uleb128(it->operand1);
805 break;
806 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
807 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
808 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
809 break;
810 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
811 if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
812 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
813 this->_encodedData.append_uleb128(it->operand1);
814 this->_encodedData.append_uleb128(it->operand2);
815 break;
816 }
817 }
818
819 // align to pointer size
820 this->_encodedData.pad_to_size(sizeof(pint_t));
821
822 this->_encoded = true;
823
824 if (log) fprintf(stderr, "total weak binding info size = %ld\n", this->_encodedData.size());
825
826 }
827
828
829
830 template <typename A>
831 class LazyBindingInfoAtom : public LinkEditAtom
832 {
833 public:
834 LazyBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
835 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) {_encoded = true; }
836
837 // overrides of ld::Atom
838 virtual const char* name() const { return "lazy binding info"; }
839 // overrides of LinkEditAtom
840 virtual void encode() const;
841
842 private:
843 typedef typename A::P P;
844 typedef typename A::P::E E;
845 typedef typename A::P::uint_t pint_t;
846
847 static ld::Section _s_section;
848 };
849
850 template <typename A>
851 ld::Section LazyBindingInfoAtom<A>::_s_section("__LINKEDIT", "__lazy_binding", ld::Section::typeLinkEdit, true);
852
853
854
855 template <typename A>
856 void LazyBindingInfoAtom<A>::encode() const
857 {
858 // stream all lazy bindings and record start offsets
859 std::vector<OutputFile::BindingInfo>& info = this->_writer._lazyBindingInfo;
860 for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
861 // record start offset for use by stub helper
862 this->_writer.setLazyBindingInfoOffset(it->_address, this->_encodedData.size());
863
864 // write address to bind
865 uint64_t segStart = 0;
866 uint64_t segEnd = 0;
867 uint32_t segIndex = 0;
868 if ( ! this->_writer.findSegment(this->_state, it->_address, &segStart, &segEnd, &segIndex) )
869 throw "lazy binding address outside range of any segment";
870 this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
871 this->_encodedData.append_uleb128(it->_address - segStart);
872
873 // write ordinal
874 if ( it->_libraryOrdinal <= 0 ) {
875 // special lookups are encoded as negative numbers in BindingInfo
876 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->_libraryOrdinal & BIND_IMMEDIATE_MASK) );
877 }
878 else if ( it->_libraryOrdinal <= 15 ) {
879 // small ordinals are encoded in opcode
880 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->_libraryOrdinal);
881 }
882 else {
883 this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
884 this->_encodedData.append_uleb128(it->_libraryOrdinal);
885 }
886 // write symbol name
887 this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->_flags);
888 this->_encodedData.append_string(it->_symbolName);
889 // write do bind
890 this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
891 this->_encodedData.append_byte(BIND_OPCODE_DONE);
892 }
893
894 // align to pointer size
895 this->_encodedData.pad_to_size(sizeof(pint_t));
896
897 this->_encoded = true;
898 //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", _encodedData.size(), allLazys.size());
899 }
900
901
902
903 template <typename A>
904 class ExportInfoAtom : public LinkEditAtom
905 {
906 public:
907 ExportInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
908 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
909
910 // overrides of ld::Atom
911 virtual const char* name() const { return "export info"; }
912 // overrides of LinkEditAtom
913 virtual void encode() const;
914
915 private:
916 typedef typename A::P P;
917 typedef typename A::P::E E;
918 typedef typename A::P::uint_t pint_t;
919
920 const ld::Atom* stubForResolverFunction(const ld::Atom* resolver) const;
921
922 struct TrieEntriesSorter
923 {
924 TrieEntriesSorter(const Options& o) : _options(o) {}
925
926 bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
927 {
928 unsigned int leftOrder;
929 unsigned int rightOrder;
930 _options.exportedSymbolOrder(left.name, &leftOrder);
931 _options.exportedSymbolOrder(right.name, &rightOrder);
932 if ( leftOrder != rightOrder )
933 return (leftOrder < rightOrder);
934 else
935 return (left.address < right.address);
936 }
937 private:
938 const Options& _options;
939 };
940
941 static ld::Section _s_section;
942 };
943
944 template <typename A>
945 ld::Section ExportInfoAtom<A>::_s_section("__LINKEDIT", "__export", ld::Section::typeLinkEdit, true);
946
947 template <typename A>
948 const ld::Atom* ExportInfoAtom<A>::stubForResolverFunction(const ld::Atom* resolver) const
949 {
950 for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
951 ld::Internal::FinalSection* sect = *sit;
952 if ( (sect->type() == ld::Section::typeStub) || (sect->type() == ld::Section::typeStubClose) ) {
953 for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
954 const ld::Atom* atom = *ait;
955 if ( strcmp(atom->name(), resolver->name()) == 0 )
956 return atom;
957 }
958 }
959 }
960 assert(0 && "no stub for resolver function");
961 return NULL;
962 }
963
964
965 template <typename A>
966 void ExportInfoAtom<A>::encode() const
967 {
968 // make vector of mach_o::trie::Entry for all exported symbols
969 std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
970 uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
971 std::vector<mach_o::trie::Entry> entries;
972 entries.reserve(exports.size());
973 for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
974 const ld::Atom* atom = *it;
975 mach_o::trie::Entry entry;
976 uint64_t flags = (atom->contentType() == ld::Atom::typeTLV) ? EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
977 uint64_t other = 0;
978 uint64_t address = atom->finalAddress() - imageBaseAddress;
979 if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
980 flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
981 if ( atom->definition() == ld::Atom::definitionProxy ) {
982 entry.name = atom->name();
983 entry.flags = flags | EXPORT_SYMBOL_FLAGS_REEXPORT;
984 entry.other = this->_writer.compressedOrdinalForAtom(atom);
985 if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) {
986 warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path());
987 continue;
988 }
989 if ( atom->isAlias() ) {
990 // alias proxy means symbol was re-exported with a name change
991 const ld::Atom* aliasOf = NULL;
992 for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
993 if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
994 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
995 aliasOf = fit->u.target;
996 }
997 }
998 assert(aliasOf != NULL);
999 entry.importName = aliasOf->name();
1000 }
1001 else {
1002 // symbol name stays same as re-export
1003 entry.importName = atom->name();
1004 }
1005 entries.push_back(entry);
1006 //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
1007 }
1008 else {
1009 if ( atom->isThumb() )
1010 address |= 1;
1011 if ( atom->contentType() == ld::Atom::typeResolver ) {
1012 flags |= EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER;
1013 // set normal lookup to return stub address
1014 // and add resolver function in new location that newer dyld's can access
1015 other = address;
1016 const ld::Atom* stub = stubForResolverFunction(atom);
1017 address = stub->finalAddress() - imageBaseAddress;
1018 if ( stub->isThumb() )
1019 address |= 1;
1020 }
1021 entry.name = atom->name();
1022 entry.flags = flags;
1023 entry.address = address;
1024 entry.other = other;
1025 entry.importName = NULL;
1026 entries.push_back(entry);
1027 }
1028 }
1029
1030 // sort vector by -exported_symbols_order, and any others by address
1031 std::sort(entries.begin(), entries.end(), TrieEntriesSorter(_options));
1032
1033 // create trie
1034 mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
1035
1036 // align to pointer size
1037 this->_encodedData.pad_to_size(sizeof(pint_t));
1038
1039 this->_encoded = true;
1040 }
1041
1042
1043 template <typename A>
1044 class SplitSegInfoAtom : public LinkEditAtom
1045 {
1046 public:
1047 SplitSegInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
1048 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
1049
1050 // overrides of ld::Atom
1051 virtual const char* name() const { return "split seg info"; }
1052 // overrides of LinkEditAtom
1053 virtual void encode() const;
1054
1055 private:
1056 typedef typename A::P P;
1057 typedef typename A::P::E E;
1058 typedef typename A::P::uint_t pint_t;
1059
1060 void addSplitSegInfo(uint64_t address, ld::Fixup::Kind k, uint32_t) const;
1061 void uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const;
1062
1063 mutable std::vector<uint64_t> _32bitPointerLocations;
1064 mutable std::vector<uint64_t> _64bitPointerLocations;
1065 mutable std::vector<uint64_t> _thumbLo16Locations;
1066 mutable std::vector<uint64_t> _thumbHi16Locations[16];
1067 mutable std::vector<uint64_t> _armLo16Locations;
1068 mutable std::vector<uint64_t> _armHi16Locations[16];
1069
1070
1071 static ld::Section _s_section;
1072 };
1073
1074 template <typename A>
1075 ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
1076
1077 template <>
1078 void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
1079 {
1080 switch (kind) {
1081 case ld::Fixup::kindStoreX86PCRel32:
1082 case ld::Fixup::kindStoreX86PCRel32_1:
1083 case ld::Fixup::kindStoreX86PCRel32_2:
1084 case ld::Fixup::kindStoreX86PCRel32_4:
1085 case ld::Fixup::kindStoreX86PCRel32GOTLoad:
1086 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
1087 case ld::Fixup::kindStoreX86PCRel32GOT:
1088 case ld::Fixup::kindStoreLittleEndian32:
1089 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
1090 case ld::Fixup::kindStoreTargetAddressX86PCRel32:
1091 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
1092 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
1093 _32bitPointerLocations.push_back(address);
1094 break;
1095 case ld::Fixup::kindStoreLittleEndian64:
1096 case ld::Fixup::kindStoreTargetAddressLittleEndian64:
1097 _64bitPointerLocations.push_back(address);
1098 break;
1099 default:
1100 warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
1101 break;
1102 }
1103 }
1104
1105 template <>
1106 void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
1107 {
1108 switch (kind) {
1109 case ld::Fixup::kindStoreLittleEndian32:
1110 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
1111 _32bitPointerLocations.push_back(address);
1112 break;
1113 default:
1114 warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
1115 break;
1116 }
1117 }
1118
1119 template <>
1120 void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
1121 {
1122 switch (kind) {
1123 case ld::Fixup::kindStoreLittleEndian32:
1124 _32bitPointerLocations.push_back(address);
1125 break;
1126 case ld::Fixup::kindStoreARMLow16:
1127 _armLo16Locations.push_back(address);
1128 break;
1129 case ld::Fixup::kindStoreThumbLow16:
1130 _thumbLo16Locations.push_back(address);
1131 break;
1132 case ld::Fixup::kindStoreARMHigh16:
1133 assert(extra < 16);
1134 _armHi16Locations[extra].push_back(address);
1135 break;
1136 case ld::Fixup::kindStoreThumbHigh16:
1137 assert(extra < 16);
1138 _thumbHi16Locations[extra].push_back(address);
1139 break;
1140 default:
1141 warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
1142 break;
1143 }
1144 }
1145
1146
1147
1148 template <typename A>
1149 void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
1150 {
1151 pint_t addr = this->_options.baseAddress();
1152 for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
1153 pint_t nextAddr = *it;
1154 //fprintf(stderr, "nextAddr=0x%0llX\n", (uint64_t)nextAddr);
1155 uint64_t delta = nextAddr - addr;
1156 //fprintf(stderr, "delta=0x%0llX\n", delta);
1157 if ( delta == 0 )
1158 throw "double split seg info for same address";
1159 // uleb128 encode
1160 uint8_t byte;
1161 do {
1162 byte = delta & 0x7F;
1163 delta &= ~0x7F;
1164 if ( delta != 0 )
1165 byte |= 0x80;
1166 this->_encodedData.append_byte(byte);
1167 delta = delta >> 7;
1168 }
1169 while( byte >= 0x80 );
1170 addr = nextAddr;
1171 }
1172 }
1173
1174
1175 template <typename A>
1176 void SplitSegInfoAtom<A>::encode() const
1177 {
1178 // sort into group by pointer adjustment kind
1179 std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
1180 for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
1181 this->addSplitSegInfo(it->address, it->kind, it->extra);
1182 }
1183
1184 // delta compress runs of addresses
1185 this->_encodedData.reserve(8192);
1186 if ( _32bitPointerLocations.size() != 0 ) {
1187 this->_encodedData.append_byte(1);
1188 //fprintf(stderr, "type 1:\n");
1189 std::sort(_32bitPointerLocations.begin(), _32bitPointerLocations.end());
1190 this->uleb128EncodeAddresses(_32bitPointerLocations);
1191 this->_encodedData.append_byte(0); // terminator
1192 }
1193
1194 if ( _64bitPointerLocations.size() != 0 ) {
1195 this->_encodedData.append_byte(2);
1196 //fprintf(stderr, "type 2:\n");
1197 std::sort(_64bitPointerLocations.begin(), _64bitPointerLocations.end());
1198 this->uleb128EncodeAddresses(_64bitPointerLocations);
1199 this->_encodedData.append_byte(0); // terminator
1200 }
1201
1202 if ( _thumbLo16Locations.size() != 0 ) {
1203 this->_encodedData.append_byte(5);
1204 //fprintf(stderr, "type 5:\n");
1205 std::sort(_thumbLo16Locations.begin(), _thumbLo16Locations.end());
1206 this->uleb128EncodeAddresses(_thumbLo16Locations);
1207 this->_encodedData.append_byte(0); // terminator
1208 }
1209
1210 if ( _armLo16Locations.size() != 0 ) {
1211 this->_encodedData.append_byte(6);
1212 //fprintf(stderr, "type 6:\n");
1213 std::sort(_armLo16Locations.begin(), _armLo16Locations.end());
1214 this->uleb128EncodeAddresses(_armLo16Locations);
1215 this->_encodedData.append_byte(0); // terminator
1216 }
1217
1218 for (uint32_t i=0; i < 16; ++i) {
1219 if ( _thumbHi16Locations[i].size() != 0 ) {
1220 this->_encodedData.append_byte(16+i);
1221 //fprintf(stderr, "type 16+%d:\n", i);
1222 std::sort(_thumbHi16Locations[i].begin(), _thumbHi16Locations[i].end());
1223 this->uleb128EncodeAddresses(_thumbHi16Locations[i]);
1224 this->_encodedData.append_byte(0); // terminator
1225 }
1226 }
1227
1228 for (uint32_t i=0; i < 16; ++i) {
1229 if ( _armHi16Locations[i].size() != 0 ) {
1230 this->_encodedData.append_byte(32+i);
1231 //fprintf(stderr, "type 32+%d:\n", i);
1232 std::sort(_armHi16Locations[i].begin(), _armHi16Locations[i].end());
1233 this->uleb128EncodeAddresses(_armHi16Locations[i]);
1234 this->_encodedData.append_byte(0); // terminator
1235 }
1236 }
1237
1238 // always add zero byte to mark end
1239 this->_encodedData.append_byte(0);
1240
1241 // align to pointer size
1242 this->_encodedData.pad_to_size(sizeof(pint_t));
1243
1244 this->_encoded = true;
1245
1246 // clean up temporaries
1247 _32bitPointerLocations.clear();
1248 _64bitPointerLocations.clear();
1249 }
1250
1251 template <typename A>
1252 class FunctionStartsAtom : public LinkEditAtom
1253 {
1254 public:
1255 FunctionStartsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
1256 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
1257
1258 // overrides of ld::Atom
1259 virtual const char* name() const { return "function starts"; }
1260 // overrides of LinkEditAtom
1261 virtual void encode() const;
1262
1263 private:
1264 typedef typename A::P P;
1265 typedef typename A::P::E E;
1266 typedef typename A::P::uint_t pint_t;
1267
1268 static ld::Section _s_section;
1269 };
1270
1271 template <typename A>
1272 ld::Section FunctionStartsAtom<A>::_s_section("__LINKEDIT", "__funcStarts", ld::Section::typeLinkEdit, true);
1273
1274
1275 template <typename A>
1276 void FunctionStartsAtom<A>::encode() const
1277 {
1278 this->_encodedData.reserve(8192);
1279 const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF;
1280 uint64_t addr = badAddress;
1281 // delta compress all function addresses
1282 for (std::vector<ld::Internal::FinalSection*>::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) {
1283 ld::Internal::FinalSection* sect = *it;
1284 if ( sect->type() == ld::Section::typeMachHeader ) {
1285 // start with delta from start of __TEXT
1286 addr = sect->address;
1287 }
1288 else if ( sect->type() == ld::Section::typeCode ) {
1289 assert(addr != badAddress);
1290 std::vector<const ld::Atom*>& atoms = sect->atoms;
1291 for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
1292 const ld::Atom* atom = *ait;
1293 // <rdar://problem/10422823> filter out zero-length atoms, so LC_FUNCTION_STARTS address can't spill into next section
1294 if ( atom->size() == 0 )
1295 continue;
1296 uint64_t nextAddr = atom->finalAddress();
1297 if ( atom->isThumb() )
1298 nextAddr |= 1;
1299 uint64_t delta = nextAddr - addr;
1300 if ( delta != 0 )
1301 this->_encodedData.append_uleb128(delta);
1302 addr = nextAddr;
1303 }
1304 }
1305 }
1306
1307 // terminator
1308 this->_encodedData.append_byte(0);
1309
1310 // align to pointer size
1311 this->_encodedData.pad_to_size(sizeof(pint_t));
1312
1313 this->_encoded = true;
1314 }
1315
1316
1317 // <rdar://problem/9218847> Need way to formalize data in code
1318 template <typename A>
1319 class DataInCodeAtom : public LinkEditAtom
1320 {
1321 public:
1322 DataInCodeAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
1323 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
1324
1325 // overrides of ld::Atom
1326 virtual const char* name() const { return "data-in-code info"; }
1327 // overrides of LinkEditAtom
1328 virtual void encode() const;
1329
1330 private:
1331 typedef typename A::P P;
1332 typedef typename A::P::E E;
1333 typedef typename A::P::uint_t pint_t;
1334
1335 struct FixupByAddressSorter
1336 {
1337 bool operator()(const ld::Fixup* left, const ld::Fixup* right)
1338 {
1339 return (left->offsetInAtom < right->offsetInAtom);
1340 }
1341 };
1342
1343 void encodeEntry(uint32_t startImageOffset, int len, ld::Fixup::Kind kind) const {
1344 //fprintf(stderr, "encodeEntry(start=0x%08X, len=0x%04X, kind=%04X\n", startImageOffset, len, kind);
1345 do {
1346 macho_data_in_code_entry<P> entry;
1347 entry.set_offset(startImageOffset);
1348 entry.set_length(len);
1349 switch ( kind ) {
1350 case ld::Fixup::kindDataInCodeStartData:
1351 entry.set_kind(DICE_KIND_DATA);
1352 break;
1353 case ld::Fixup::kindDataInCodeStartJT8:
1354 entry.set_kind(DICE_KIND_JUMP_TABLE8);
1355 break;
1356 case ld::Fixup::kindDataInCodeStartJT16:
1357 entry.set_kind(DICE_KIND_JUMP_TABLE16);
1358 break;
1359 case ld::Fixup::kindDataInCodeStartJT32:
1360 entry.set_kind(DICE_KIND_JUMP_TABLE32);
1361 break;
1362 case ld::Fixup::kindDataInCodeStartJTA32:
1363 entry.set_kind(DICE_KIND_ABS_JUMP_TABLE32);
1364 break;
1365 default:
1366 assert(0 && "bad L$start$ label to encode");
1367 }
1368 uint8_t* bp = (uint8_t*)&entry;
1369 this->_encodedData.append_byte(bp[0]);
1370 this->_encodedData.append_byte(bp[1]);
1371 this->_encodedData.append_byte(bp[2]);
1372 this->_encodedData.append_byte(bp[3]);
1373 this->_encodedData.append_byte(bp[4]);
1374 this->_encodedData.append_byte(bp[5]);
1375 this->_encodedData.append_byte(bp[6]);
1376 this->_encodedData.append_byte(bp[7]);
1377 // in rare case data range is huge, create multiple entries
1378 len -= 0xFFF8;
1379 startImageOffset += 0xFFF8;
1380 } while ( len > 0 );
1381 }
1382
1383 static ld::Section _s_section;
1384 };
1385
1386 template <typename A>
1387 ld::Section DataInCodeAtom<A>::_s_section("__LINKEDIT", "__dataInCode", ld::Section::typeLinkEdit, true);
1388
1389
1390 template <typename A>
1391 void DataInCodeAtom<A>::encode() const
1392 {
1393 if ( this->_writer.hasDataInCode ) {
1394 uint64_t mhAddress = 0;
1395 for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
1396 ld::Internal::FinalSection* sect = *sit;
1397 if ( sect->type() == ld::Section::typeMachHeader )
1398 mhAddress = sect->address;
1399 if ( sect->type() != ld::Section::typeCode )
1400 continue;
1401 for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
1402 const ld::Atom* atom = *ait;
1403 // gather all code-in-data labels
1404 std::vector<const ld::Fixup*> dataInCodeLabels;
1405 for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
1406 switch ( fit->kind ) {
1407 case ld::Fixup::kindDataInCodeStartData:
1408 case ld::Fixup::kindDataInCodeStartJT8:
1409 case ld::Fixup::kindDataInCodeStartJT16:
1410 case ld::Fixup::kindDataInCodeStartJT32:
1411 case ld::Fixup::kindDataInCodeStartJTA32:
1412 case ld::Fixup::kindDataInCodeEnd:
1413 dataInCodeLabels.push_back(fit);
1414 break;
1415 default:
1416 break;
1417 }
1418 }
1419 // to do: sort labels by address
1420 std::sort(dataInCodeLabels.begin(), dataInCodeLabels.end(), FixupByAddressSorter());
1421
1422 // convert to array of struct data_in_code_entry
1423 ld::Fixup::Kind prevKind = ld::Fixup::kindDataInCodeEnd;
1424 uint32_t prevOffset = 0;
1425 for ( std::vector<const ld::Fixup*>::iterator sfit = dataInCodeLabels.begin(); sfit != dataInCodeLabels.end(); ++sfit) {
1426 if ( ((*sfit)->kind != prevKind) && (prevKind != ld::Fixup::kindDataInCodeEnd) ) {
1427 int len = (*sfit)->offsetInAtom - prevOffset;
1428 if ( len == 0 )
1429 warning("multiple L$start$ labels found at same address in %s at offset 0x%04X", atom->name(), prevOffset);
1430 this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, (*sfit)->offsetInAtom - prevOffset, prevKind);
1431 }
1432 prevKind = (*sfit)->kind;
1433 prevOffset = (*sfit)->offsetInAtom;
1434 }
1435 if ( prevKind != ld::Fixup::kindDataInCodeEnd ) {
1436 // add entry if function ends with data
1437 this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, atom->size() - prevOffset, prevKind);
1438 }
1439 }
1440 }
1441 }
1442
1443 this->_encoded = true;
1444 }
1445
1446
1447
1448
1449
1450 // <rdar://problem/7209249> linker needs to cache "Designated Requirements" in linked binary
1451 template <typename A>
1452 class DependentDRAtom : public LinkEditAtom
1453 {
1454 public:
1455 DependentDRAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
1456 : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
1457
1458 // overrides of ld::Atom
1459 virtual const char* name() const { return "dependent dylib DR info"; }
1460 // overrides of LinkEditAtom
1461 virtual void encode() const;
1462
1463 private:
1464 typedef typename A::P P;
1465 typedef typename A::P::E E;
1466 typedef typename A::P::uint_t pint_t;
1467
1468 static ld::Section _s_section;
1469
1470 };
1471
1472 template <typename A>
1473 ld::Section DependentDRAtom<A>::_s_section("__LINKEDIT", "__dependentDR", ld::Section::typeLinkEdit, true);
1474
1475
1476 template <typename A>
1477 void DependentDRAtom<A>::encode() const
1478 {
1479 Security::SuperBlobCore<Security::SuperBlob<Security::kSecCodeMagicDRList>, Security::kSecCodeMagicDRList, uint32_t>::Maker maker;
1480
1481 uint32_t index = 0;
1482 for(std::vector<ld::dylib::File*>::iterator it=_state.dylibs.begin(); it != _state.dylibs.end(); ++it) {
1483 const ld::dylib::File* dylib = *it;
1484 Security::BlobCore* dylibDR = (Security::BlobCore*)dylib->codeSignatureDR();
1485 void* dup = NULL;
1486 if ( dylibDR != NULL ) {
1487 // <rdar://problem/11315321> Maker takes ownership of every blob added
1488 // We need to make a copy here because dylib still owns the pointer returned by codeSignatureDR()
1489 dup = ::malloc(dylibDR->length());
1490 ::memcpy(dup, dylibDR, dylibDR->length());
1491 }
1492 maker.add(index, (Security::BlobCore*)dup);
1493 ++index;
1494 }
1495
1496 Security::SuperBlob<Security::kSecCodeMagicDRList>* topBlob = maker.make();
1497 const uint8_t* data = (uint8_t*)topBlob->data();
1498 for(size_t i=0; i < topBlob->length(); ++i)
1499 _encodedData.append_byte(data[i]);
1500
1501 this->_encodedData.pad_to_size(sizeof(pint_t));
1502
1503 this->_encoded = true;
1504 }
1505
1506
1507
1508 } // namespace tool
1509 } // namespace ld
1510
1511 #endif // __LINKEDIT_HPP__