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