1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
3 * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/types.h>
30 #include <sys/sysctl.h>
31 #include <sys/param.h>
32 #include <sys/mount.h>
37 #include <mach/mach_time.h>
38 #include <mach/vm_statistics.h>
39 #include <mach/mach_init.h>
40 #include <mach/mach_host.h>
41 #include <uuid/uuid.h>
43 #include <mach-o/dyld.h>
44 #include <mach-o/fat.h>
53 #include <unordered_set>
55 #include <CommonCrypto/CommonDigest.h>
56 #include <AvailabilityMacros.h>
58 #include "MachOTrie.hpp"
62 #include "OutputFile.h"
63 #include "Architectures.hpp"
64 #include "HeaderAndLoadCommands.hpp"
65 #include "LinkEdit.hpp"
66 #include "LinkEditClassic.hpp"
73 uint32_t sAdrpNoped
= 0;
74 uint32_t sAdrpNotNoped
= 0;
77 OutputFile::OutputFile(const Options
& opts
)
79 usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false),
80 _noReExportedDylibs(false), pieDisabled(false), hasDataInCode(false),
81 headerAndLoadCommandsSection(NULL
),
82 rebaseSection(NULL
), bindingSection(NULL
), weakBindingSection(NULL
),
83 lazyBindingSection(NULL
), exportSection(NULL
),
84 splitSegInfoSection(NULL
), functionStartsSection(NULL
),
85 dataInCodeSection(NULL
), optimizationHintsSection(NULL
), dependentDRsSection(NULL
),
86 symbolTableSection(NULL
), stringPoolSection(NULL
),
87 localRelocationsSection(NULL
), externalRelocationsSection(NULL
),
88 sectionRelocationsSection(NULL
),
89 indirectSymbolTableSection(NULL
),
91 _hasDyldInfo(opts
.makeCompressedDyldInfo()),
92 _hasSymbolTable(true),
93 _hasSectionRelocations(opts
.outputKind() == Options::kObjectFile
),
94 _hasSplitSegInfo(opts
.sharedRegionEligible()),
95 _hasFunctionStartsInfo(opts
.addFunctionStarts()),
96 _hasDataInCodeInfo(opts
.addDataInCodeInfo()),
97 _hasDependentDRInfo(opts
.needsDependentDRInfo()),
98 _hasDynamicSymbolTable(true),
99 _hasLocalRelocations(!opts
.makeCompressedDyldInfo()),
100 _hasExternalRelocations(!opts
.makeCompressedDyldInfo()),
101 _hasOptimizationHints(opts
.outputKind() == Options::kObjectFile
),
102 _encryptedTEXTstartOffset(0),
103 _encryptedTEXTendOffset(0),
104 _localSymbolsStartIndex(0),
105 _localSymbolsCount(0),
106 _globalSymbolsStartIndex(0),
107 _globalSymbolsCount(0),
108 _importSymbolsStartIndex(0),
109 _importSymbolsCount(0),
110 _sectionsRelocationsAtom(NULL
),
111 _localRelocsAtom(NULL
),
112 _externalRelocsAtom(NULL
),
113 _symbolTableAtom(NULL
),
114 _indirectSymbolTableAtom(NULL
),
115 _rebasingInfoAtom(NULL
),
116 _bindingInfoAtom(NULL
),
117 _lazyBindingInfoAtom(NULL
),
118 _weakBindingInfoAtom(NULL
),
119 _exportInfoAtom(NULL
),
120 _splitSegInfoAtom(NULL
),
121 _functionStartsAtom(NULL
),
122 _dataInCodeAtom(NULL
),
123 _dependentDRInfoAtom(NULL
),
124 _optimizationHintsAtom(NULL
)
128 void OutputFile::dumpAtomsBySection(ld::Internal
& state
, bool printAtoms
)
130 fprintf(stderr
, "SORTED:\n");
131 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
132 fprintf(stderr
, "final section %p %s/%s %s start addr=0x%08llX, size=0x%08llX, alignment=%02d, fileOffset=0x%08llX\n",
133 (*it
), (*it
)->segmentName(), (*it
)->sectionName(), (*it
)->isSectionHidden() ? "(hidden)" : "",
134 (*it
)->address
, (*it
)->size
, (*it
)->alignment
, (*it
)->fileOffset
);
136 std::vector
<const ld::Atom
*>& atoms
= (*it
)->atoms
;
137 for (std::vector
<const ld::Atom
*>::iterator ait
= atoms
.begin(); ait
!= atoms
.end(); ++ait
) {
138 fprintf(stderr
, " %p (0x%04llX) %s\n", *ait
, (*ait
)->size(), (*ait
)->name());
142 fprintf(stderr
, "DYLIBS:\n");
143 for (std::vector
<ld::dylib::File
*>::iterator it
=state
.dylibs
.begin(); it
!= state
.dylibs
.end(); ++it
)
144 fprintf(stderr
, " %s\n", (*it
)->installPath());
147 void OutputFile::write(ld::Internal
& state
)
149 this->buildDylibOrdinalMapping(state
);
150 this->addLoadCommands(state
);
151 this->addLinkEdit(state
);
152 state
.setSectionSizesAndAlignments();
153 this->setLoadCommandsPadding(state
);
154 _fileSize
= state
.assignFileOffsets();
155 this->assignAtomAddresses(state
);
156 this->synthesizeDebugNotes(state
);
157 this->buildSymbolTable(state
);
158 this->generateLinkEditInfo(state
);
159 this->makeSplitSegInfo(state
);
160 this->updateLINKEDITAddresses(state
);
161 //this->dumpAtomsBySection(state, false);
162 this->writeOutputFile(state
);
163 this->writeMapFile(state
);
166 bool OutputFile::findSegment(ld::Internal
& state
, uint64_t addr
, uint64_t* start
, uint64_t* end
, uint32_t* index
)
168 uint32_t segIndex
= 0;
169 ld::Internal::FinalSection
* segFirstSection
= NULL
;
170 ld::Internal::FinalSection
* lastSection
= NULL
;
171 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
172 ld::Internal::FinalSection
* sect
= *it
;
173 if ( (segFirstSection
== NULL
) || strcmp(segFirstSection
->segmentName(), sect
->segmentName()) != 0 ) {
174 if ( segFirstSection
!= NULL
) {
175 //fprintf(stderr, "findSegment(0x%llX) seg changed to %s\n", addr, sect->segmentName());
176 if ( (addr
>= segFirstSection
->address
) && (addr
< lastSection
->address
+lastSection
->size
) ) {
177 *start
= segFirstSection
->address
;
178 *end
= lastSection
->address
+lastSection
->size
;
184 segFirstSection
= sect
;
192 void OutputFile::assignAtomAddresses(ld::Internal
& state
)
194 const bool log
= false;
195 if ( log
) fprintf(stderr
, "assignAtomAddresses()\n");
196 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
197 ld::Internal::FinalSection
* sect
= *sit
;
198 if ( log
) fprintf(stderr
, " section=%s/%s\n", sect
->segmentName(), sect
->sectionName());
199 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
200 const ld::Atom
* atom
= *ait
;
201 switch ( sect
-> type() ) {
202 case ld::Section::typeImportProxies
:
203 // want finalAddress() of all proxy atoms to be zero
204 (const_cast<ld::Atom
*>(atom
))->setSectionStartAddress(0);
206 case ld::Section::typeAbsoluteSymbols
:
207 // want finalAddress() of all absolute atoms to be value of abs symbol
208 (const_cast<ld::Atom
*>(atom
))->setSectionStartAddress(0);
210 case ld::Section::typeLinkEdit
:
211 // linkedit layout is assigned later
214 (const_cast<ld::Atom
*>(atom
))->setSectionStartAddress(sect
->address
);
215 if ( log
) fprintf(stderr
, " atom=%p, addr=0x%08llX, name=%s\n", atom
, atom
->finalAddress(), atom
->name());
222 void OutputFile::updateLINKEDITAddresses(ld::Internal
& state
)
224 if ( _options
.makeCompressedDyldInfo() ) {
225 // build dylb rebasing info
226 assert(_rebasingInfoAtom
!= NULL
);
227 _rebasingInfoAtom
->encode();
229 // build dyld binding info
230 assert(_bindingInfoAtom
!= NULL
);
231 _bindingInfoAtom
->encode();
233 // build dyld lazy binding info
234 assert(_lazyBindingInfoAtom
!= NULL
);
235 _lazyBindingInfoAtom
->encode();
237 // build dyld weak binding info
238 assert(_weakBindingInfoAtom
!= NULL
);
239 _weakBindingInfoAtom
->encode();
241 // build dyld export info
242 assert(_exportInfoAtom
!= NULL
);
243 _exportInfoAtom
->encode();
246 if ( _options
.sharedRegionEligible() ) {
247 // build split seg info
248 assert(_splitSegInfoAtom
!= NULL
);
249 _splitSegInfoAtom
->encode();
252 if ( _options
.addFunctionStarts() ) {
253 // build function starts info
254 assert(_functionStartsAtom
!= NULL
);
255 _functionStartsAtom
->encode();
258 if ( _options
.addDataInCodeInfo() ) {
259 // build data-in-code info
260 assert(_dataInCodeAtom
!= NULL
);
261 _dataInCodeAtom
->encode();
264 if ( _hasOptimizationHints
) {
265 // build linker-optimization-hint info
266 assert(_optimizationHintsAtom
!= NULL
);
267 _optimizationHintsAtom
->encode();
270 if ( _options
.needsDependentDRInfo() ) {
271 // build dependent dylib DR info
272 assert(_dependentDRInfoAtom
!= NULL
);
273 _dependentDRInfoAtom
->encode();
276 // build classic symbol table
277 assert(_symbolTableAtom
!= NULL
);
278 _symbolTableAtom
->encode();
279 assert(_indirectSymbolTableAtom
!= NULL
);
280 _indirectSymbolTableAtom
->encode();
282 // add relocations to .o files
283 if ( _options
.outputKind() == Options::kObjectFile
) {
284 assert(_sectionsRelocationsAtom
!= NULL
);
285 _sectionsRelocationsAtom
->encode();
288 if ( ! _options
.makeCompressedDyldInfo() ) {
289 // build external relocations
290 assert(_externalRelocsAtom
!= NULL
);
291 _externalRelocsAtom
->encode();
292 // build local relocations
293 assert(_localRelocsAtom
!= NULL
);
294 _localRelocsAtom
->encode();
297 // update address and file offsets now that linkedit content has been generated
298 uint64_t curLinkEditAddress
= 0;
299 uint64_t curLinkEditfileOffset
= 0;
300 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
301 ld::Internal::FinalSection
* sect
= *sit
;
302 if ( sect
->type() != ld::Section::typeLinkEdit
)
304 if ( curLinkEditAddress
== 0 ) {
305 curLinkEditAddress
= sect
->address
;
306 curLinkEditfileOffset
= sect
->fileOffset
;
308 uint16_t maxAlignment
= 0;
310 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
311 const ld::Atom
* atom
= *ait
;
312 //fprintf(stderr, "setting linkedit atom offset for %s\n", atom->name());
313 if ( atom
->alignment().powerOf2
> maxAlignment
)
314 maxAlignment
= atom
->alignment().powerOf2
;
315 // calculate section offset for this atom
316 uint64_t alignment
= 1 << atom
->alignment().powerOf2
;
317 uint64_t currentModulus
= (offset
% alignment
);
318 uint64_t requiredModulus
= atom
->alignment().modulus
;
319 if ( currentModulus
!= requiredModulus
) {
320 if ( requiredModulus
> currentModulus
)
321 offset
+= requiredModulus
-currentModulus
;
323 offset
+= requiredModulus
+alignment
-currentModulus
;
325 (const_cast<ld::Atom
*>(atom
))->setSectionOffset(offset
);
326 (const_cast<ld::Atom
*>(atom
))->setSectionStartAddress(curLinkEditAddress
);
327 offset
+= atom
->size();
330 // section alignment is that of a contained atom with the greatest alignment
331 sect
->alignment
= maxAlignment
;
332 sect
->address
= curLinkEditAddress
;
333 sect
->fileOffset
= curLinkEditfileOffset
;
334 curLinkEditAddress
+= sect
->size
;
335 curLinkEditfileOffset
+= sect
->size
;
338 _fileSize
= state
.sections
.back()->fileOffset
+ state
.sections
.back()->size
;
342 void OutputFile::setLoadCommandsPadding(ld::Internal
& state
)
344 // In other sections, any extra space is put and end of segment.
345 // In __TEXT segment, any extra space is put after load commands to allow post-processing of load commands
346 // Do a reverse layout of __TEXT segment to determine padding size and adjust section size
347 uint64_t paddingSize
= 0;
348 switch ( _options
.outputKind() ) {
350 // dyld itself has special padding requirements. We want the beginning __text section to start at a stable address
351 assert(strcmp(state
.sections
[1]->sectionName(),"__text") == 0);
352 state
.sections
[1]->alignment
= 12; // page align __text
354 case Options::kObjectFile
:
355 // mach-o .o files need no padding between load commands and first section
356 // but leave enough room that the object file could be signed
359 case Options::kPreload
:
360 // mach-o MH_PRELOAD files need no padding between load commands and first section
363 // work backwards from end of segment and lay out sections so that extra room goes to padding atom
365 uint64_t textSegPageSize
= _options
.segPageSize("__TEXT");
366 for (std::vector
<ld::Internal::FinalSection
*>::reverse_iterator it
= state
.sections
.rbegin(); it
!= state
.sections
.rend(); ++it
) {
367 ld::Internal::FinalSection
* sect
= *it
;
368 if ( strcmp(sect
->segmentName(), "__TEXT") != 0 )
370 if ( sect
== headerAndLoadCommandsSection
) {
371 addr
-= headerAndLoadCommandsSection
->size
;
372 paddingSize
= addr
% textSegPageSize
;
376 addr
= addr
& (0 - (1 << sect
->alignment
));
379 // if command line requires more padding than this
380 uint32_t minPad
= _options
.minimumHeaderPad();
381 if ( _options
.maxMminimumHeaderPad() ) {
382 // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
383 uint32_t altMin
= _dylibsToLoad
.size() * MAXPATHLEN
;
384 if ( _options
.outputKind() == Options::kDynamicLibrary
)
385 altMin
+= MAXPATHLEN
;
386 if ( altMin
> minPad
)
389 if ( paddingSize
< minPad
) {
390 int extraPages
= (minPad
- paddingSize
+ _options
.segmentAlignment() - 1)/_options
.segmentAlignment();
391 paddingSize
+= extraPages
* _options
.segmentAlignment();
394 if ( _options
.makeEncryptable() ) {
395 // load commands must be on a separate non-encrypted page
396 int loadCommandsPage
= (headerAndLoadCommandsSection
->size
+ minPad
)/_options
.segmentAlignment();
397 int textPage
= (headerAndLoadCommandsSection
->size
+ paddingSize
)/_options
.segmentAlignment();
398 if ( loadCommandsPage
== textPage
) {
399 paddingSize
+= _options
.segmentAlignment();
402 // remember start for later use by load command
403 _encryptedTEXTstartOffset
= textPage
*_options
.segmentAlignment();
407 // add padding to size of section
408 headerAndLoadCommandsSection
->size
+= paddingSize
;
412 uint64_t OutputFile::pageAlign(uint64_t addr
)
414 const uint64_t alignment
= _options
.segmentAlignment();
415 return ((addr
+alignment
-1) & (-alignment
));
418 uint64_t OutputFile::pageAlign(uint64_t addr
, uint64_t pageSize
)
420 return ((addr
+pageSize
-1) & (-pageSize
));
423 static const char* makeName(const ld::Atom
& atom
)
425 static char buffer
[4096];
426 switch ( atom
.symbolTableInclusion() ) {
427 case ld::Atom::symbolTableNotIn
:
428 case ld::Atom::symbolTableNotInFinalLinkedImages
:
429 sprintf(buffer
, "%s@0x%08llX", atom
.name(), atom
.objectAddress());
431 case ld::Atom::symbolTableIn
:
432 case ld::Atom::symbolTableInAndNeverStrip
:
433 case ld::Atom::symbolTableInAsAbsolute
:
434 case ld::Atom::symbolTableInWithRandomAutoStripLabel
:
435 strlcpy(buffer
, atom
.name(), 4096);
441 static const char* referenceTargetAtomName(ld::Internal
& state
, const ld::Fixup
* ref
)
443 switch ( ref
->binding
) {
444 case ld::Fixup::bindingNone
:
446 case ld::Fixup::bindingByNameUnbound
:
447 return (char*)(ref
->u
.target
);
448 case ld::Fixup::bindingByContentBound
:
449 case ld::Fixup::bindingDirectlyBound
:
450 return makeName(*((ld::Atom
*)(ref
->u
.target
)));
451 case ld::Fixup::bindingsIndirectlyBound
:
452 return makeName(*state
.indirectBindingTable
[ref
->u
.bindingIndex
]);
454 return "BAD BINDING";
457 bool OutputFile::targetIsThumb(ld::Internal
& state
, const ld::Fixup
* fixup
)
459 switch ( fixup
->binding
) {
460 case ld::Fixup::bindingByContentBound
:
461 case ld::Fixup::bindingDirectlyBound
:
462 return fixup
->u
.target
->isThumb();
463 case ld::Fixup::bindingsIndirectlyBound
:
464 return state
.indirectBindingTable
[fixup
->u
.bindingIndex
]->isThumb();
468 throw "unexpected binding";
471 uint64_t OutputFile::addressOf(const ld::Internal
& state
, const ld::Fixup
* fixup
, const ld::Atom
** target
)
473 if ( !_options
.makeCompressedDyldInfo() ) {
474 // For external relocations the classic mach-o format
475 // has addend only stored in the content. That means
476 // that the address of the target is not used.
477 if ( fixup
->contentAddendOnly
)
480 switch ( fixup
->binding
) {
481 case ld::Fixup::bindingNone
:
482 throw "unexpected bindingNone";
483 case ld::Fixup::bindingByNameUnbound
:
484 throw "unexpected bindingByNameUnbound";
485 case ld::Fixup::bindingByContentBound
:
486 case ld::Fixup::bindingDirectlyBound
:
487 *target
= fixup
->u
.target
;
488 return (*target
)->finalAddress();
489 case ld::Fixup::bindingsIndirectlyBound
:
490 *target
= state
.indirectBindingTable
[fixup
->u
.bindingIndex
];
492 if ( ! (*target
)->finalAddressMode() ) {
493 throwf("reference to symbol (which has not been assigned an address) %s", (*target
)->name());
496 return (*target
)->finalAddress();
498 throw "unexpected binding";
501 uint64_t OutputFile::sectionOffsetOf(const ld::Internal
& state
, const ld::Fixup
* fixup
)
503 const ld::Atom
* target
= NULL
;
504 switch ( fixup
->binding
) {
505 case ld::Fixup::bindingNone
:
506 throw "unexpected bindingNone";
507 case ld::Fixup::bindingByNameUnbound
:
508 throw "unexpected bindingByNameUnbound";
509 case ld::Fixup::bindingByContentBound
:
510 case ld::Fixup::bindingDirectlyBound
:
511 target
= fixup
->u
.target
;
513 case ld::Fixup::bindingsIndirectlyBound
:
514 target
= state
.indirectBindingTable
[fixup
->u
.bindingIndex
];
517 assert(target
!= NULL
);
519 uint64_t targetAddress
= target
->finalAddress();
520 for (std::vector
<ld::Internal::FinalSection
*>::const_iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
521 const ld::Internal::FinalSection
* sect
= *it
;
522 if ( (sect
->address
<= targetAddress
) && (targetAddress
< (sect
->address
+sect
->size
)) )
523 return targetAddress
- sect
->address
;
525 throw "section not found for section offset";
530 uint64_t OutputFile::tlvTemplateOffsetOf(const ld::Internal
& state
, const ld::Fixup
* fixup
)
532 const ld::Atom
* target
= NULL
;
533 switch ( fixup
->binding
) {
534 case ld::Fixup::bindingNone
:
535 throw "unexpected bindingNone";
536 case ld::Fixup::bindingByNameUnbound
:
537 throw "unexpected bindingByNameUnbound";
538 case ld::Fixup::bindingByContentBound
:
539 case ld::Fixup::bindingDirectlyBound
:
540 target
= fixup
->u
.target
;
542 case ld::Fixup::bindingsIndirectlyBound
:
543 target
= state
.indirectBindingTable
[fixup
->u
.bindingIndex
];
546 assert(target
!= NULL
);
548 for (std::vector
<ld::Internal::FinalSection
*>::const_iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
549 const ld::Internal::FinalSection
* sect
= *it
;
550 switch ( sect
->type() ) {
551 case ld::Section::typeTLVInitialValues
:
552 case ld::Section::typeTLVZeroFill
:
553 return target
->finalAddress() - sect
->address
;
558 throw "section not found for tlvTemplateOffsetOf";
561 void OutputFile::printSectionLayout(ld::Internal
& state
)
563 // show layout of final image
564 fprintf(stderr
, "final section layout:\n");
565 for (std::vector
<ld::Internal::FinalSection
*>::iterator it
= state
.sections
.begin(); it
!= state
.sections
.end(); ++it
) {
566 if ( (*it
)->isSectionHidden() )
568 fprintf(stderr
, " %s/%s addr=0x%08llX, size=0x%08llX, fileOffset=0x%08llX, type=%d\n",
569 (*it
)->segmentName(), (*it
)->sectionName(),
570 (*it
)->address
, (*it
)->size
, (*it
)->fileOffset
, (*it
)->type());
575 void OutputFile::rangeCheck8(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
577 if ( (displacement
> 127) || (displacement
< -128) ) {
578 // show layout of final image
579 printSectionLayout(state
);
581 const ld::Atom
* target
;
582 throwf("8-bit reference out of range (%lld max is +/-127B): from %s (0x%08llX) to %s (0x%08llX)",
583 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
584 addressOf(state
, fixup
, &target
));
588 void OutputFile::rangeCheck16(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
590 const int64_t thirtyTwoKLimit
= 0x00007FFF;
591 if ( (displacement
> thirtyTwoKLimit
) || (displacement
< (-thirtyTwoKLimit
)) ) {
592 // show layout of final image
593 printSectionLayout(state
);
595 const ld::Atom
* target
;
596 throwf("16-bit reference out of range (%lld max is +/-32KB): from %s (0x%08llX) to %s (0x%08llX)",
597 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
598 addressOf(state
, fixup
, &target
));
602 void OutputFile::rangeCheckBranch32(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
604 const int64_t twoGigLimit
= 0x7FFFFFFF;
605 if ( (displacement
> twoGigLimit
) || (displacement
< (-twoGigLimit
)) ) {
606 // show layout of final image
607 printSectionLayout(state
);
609 const ld::Atom
* target
;
610 throwf("32-bit branch out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
611 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
612 addressOf(state
, fixup
, &target
));
617 void OutputFile::rangeCheckAbsolute32(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
619 const int64_t fourGigLimit
= 0xFFFFFFFF;
620 if ( displacement
> fourGigLimit
) {
621 // <rdar://problem/9610466> cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information
622 // .long _foo - 0xC0000000
623 // is encoded in mach-o the same as:
624 // .long _foo + 0x40000000
625 // so if _foo lays out to 0xC0000100, the first is ok, but the second is not.
626 if ( (_options
.architecture() == CPU_TYPE_ARM
) || (_options
.architecture() == CPU_TYPE_I386
) ) {
627 // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload or -static
628 if ( (_options
.outputKind() != Options::kPreload
) && (_options
.outputKind() != Options::kStaticExecutable
) ) {
629 warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
630 displacement
, atom
->name(), fixup
->offsetInAtom
, atom
->finalAddress(), displacement
);
634 // show layout of final image
635 printSectionLayout(state
);
637 const ld::Atom
* target
;
638 if ( fixup
->binding
== ld::Fixup::bindingNone
)
639 throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
640 displacement
, atom
->name(), fixup
->offsetInAtom
, atom
->finalAddress(), displacement
);
642 throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)",
643 displacement
, atom
->name(), fixup
->offsetInAtom
, atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
644 addressOf(state
, fixup
, &target
));
649 void OutputFile::rangeCheckRIP32(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
651 const int64_t twoGigLimit
= 0x7FFFFFFF;
652 if ( (displacement
> twoGigLimit
) || (displacement
< (-twoGigLimit
)) ) {
653 // show layout of final image
654 printSectionLayout(state
);
656 const ld::Atom
* target
;
657 throwf("32-bit RIP relative reference out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
658 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
659 addressOf(state
, fixup
, &target
));
663 void OutputFile::rangeCheckARM12(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
665 if ( (displacement
> 4092LL) || (displacement
< (-4092LL)) ) {
666 // show layout of final image
667 printSectionLayout(state
);
669 const ld::Atom
* target
;
670 throwf("ARM ldr 12-bit displacement out of range (%lld max is +/-4096B): from %s (0x%08llX) to %s (0x%08llX)",
671 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
672 addressOf(state
, fixup
, &target
));
676 bool OutputFile::checkArmBranch24Displacement(int64_t displacement
)
678 return ( (displacement
< 33554428LL) && (displacement
> (-33554432LL)) );
681 void OutputFile::rangeCheckARMBranch24(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
683 if ( checkArmBranch24Displacement(displacement
) )
686 // show layout of final image
687 printSectionLayout(state
);
689 const ld::Atom
* target
;
690 throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)",
691 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
692 addressOf(state
, fixup
, &target
));
695 bool OutputFile::checkThumbBranch22Displacement(int64_t displacement
)
697 // thumb2 supports +/- 16MB displacement
698 if ( _options
.preferSubArchitecture() && _options
.archSupportsThumb2() ) {
699 if ( (displacement
> 16777214LL) || (displacement
< (-16777216LL)) ) {
704 // thumb1 supports +/- 4MB displacement
705 if ( (displacement
> 4194302LL) || (displacement
< (-4194304LL)) ) {
712 void OutputFile::rangeCheckThumbBranch22(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
714 if ( checkThumbBranch22Displacement(displacement
) )
717 // show layout of final image
718 printSectionLayout(state
);
720 const ld::Atom
* target
;
721 if ( _options
.preferSubArchitecture() && _options
.archSupportsThumb2() ) {
722 throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)",
723 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
724 addressOf(state
, fixup
, &target
));
727 throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)",
728 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
729 addressOf(state
, fixup
, &target
));
734 void OutputFile::rangeCheckARM64Branch26(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
736 const int64_t bl_128MegLimit
= 0x07FFFFFF;
737 if ( (displacement
> bl_128MegLimit
) || (displacement
< (-bl_128MegLimit
)) ) {
738 // show layout of final image
739 printSectionLayout(state
);
741 const ld::Atom
* target
;
742 throwf("b(l) ARM64 branch out of range (%lld max is +/-128MB): from %s (0x%08llX) to %s (0x%08llX)",
743 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
744 addressOf(state
, fixup
, &target
));
748 void OutputFile::rangeCheckARM64Page21(int64_t displacement
, ld::Internal
& state
, const ld::Atom
* atom
, const ld::Fixup
* fixup
)
750 const int64_t adrp_4GigLimit
= 0x100000000ULL
;
751 if ( (displacement
> adrp_4GigLimit
) || (displacement
< (-adrp_4GigLimit
)) ) {
752 // show layout of final image
753 printSectionLayout(state
);
755 const ld::Atom
* target
;
756 throwf("ARM64 ADRP out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
757 displacement
, atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fixup
),
758 addressOf(state
, fixup
, &target
));
763 uint16_t OutputFile::get16LE(uint8_t* loc
) { return LittleEndian::get16(*(uint16_t*)loc
); }
764 void OutputFile::set16LE(uint8_t* loc
, uint16_t value
) { LittleEndian::set16(*(uint16_t*)loc
, value
); }
766 uint32_t OutputFile::get32LE(uint8_t* loc
) { return LittleEndian::get32(*(uint32_t*)loc
); }
767 void OutputFile::set32LE(uint8_t* loc
, uint32_t value
) { LittleEndian::set32(*(uint32_t*)loc
, value
); }
769 uint64_t OutputFile::get64LE(uint8_t* loc
) { return LittleEndian::get64(*(uint64_t*)loc
); }
770 void OutputFile::set64LE(uint8_t* loc
, uint64_t value
) { LittleEndian::set64(*(uint64_t*)loc
, value
); }
772 uint16_t OutputFile::get16BE(uint8_t* loc
) { return BigEndian::get16(*(uint16_t*)loc
); }
773 void OutputFile::set16BE(uint8_t* loc
, uint16_t value
) { BigEndian::set16(*(uint16_t*)loc
, value
); }
775 uint32_t OutputFile::get32BE(uint8_t* loc
) { return BigEndian::get32(*(uint32_t*)loc
); }
776 void OutputFile::set32BE(uint8_t* loc
, uint32_t value
) { BigEndian::set32(*(uint32_t*)loc
, value
); }
778 uint64_t OutputFile::get64BE(uint8_t* loc
) { return BigEndian::get64(*(uint64_t*)loc
); }
779 void OutputFile::set64BE(uint8_t* loc
, uint64_t value
) { BigEndian::set64(*(uint64_t*)loc
, value
); }
781 static uint32_t makeNOP() {
785 enum SignExtension
{ signedNot
, signed32
, signed64
};
786 struct LoadStoreInfo
{
789 uint32_t offset
; // after scaling
790 uint32_t size
; // 1,2,4,8, or 16
792 bool isFloat
; // if destReg is FP/SIMD
793 SignExtension signEx
; // if load is sign extended
796 static uint32_t makeLDR_literal(const LoadStoreInfo
& info
, uint64_t targetAddress
, uint64_t instructionAddress
)
798 int64_t delta
= targetAddress
- instructionAddress
;
799 assert(delta
< 1024*1024);
800 assert(delta
> -1024*1024);
801 assert((info
.reg
& 0xFFFFFFE0) == 0);
802 assert((targetAddress
& 0x3) == 0);
803 assert((instructionAddress
& 0x3) == 0);
804 assert(!info
.isStore
);
805 uint32_t imm19
= (delta
<< 3) & 0x00FFFFE0;
806 uint32_t instruction
= 0;
807 switch ( info
.size
) {
809 if ( info
.isFloat
) {
810 assert(info
.signEx
== signedNot
);
811 instruction
= 0x1C000000;
814 if ( info
.signEx
== signed64
)
815 instruction
= 0x98000000;
817 instruction
= 0x18000000;
821 assert(info
.signEx
== signedNot
);
822 instruction
= info
.isFloat
? 0x5C000000 : 0x58000000;
825 assert(info
.signEx
== signedNot
);
826 instruction
= 0x9C000000;
829 assert(0 && "invalid load size for literal");
831 return (instruction
| imm19
| info
.reg
);
834 static uint32_t makeADR(uint32_t destReg
, uint64_t targetAddress
, uint64_t instructionAddress
)
836 assert((destReg
& 0xFFFFFFE0) == 0);
837 assert((instructionAddress
& 0x3) == 0);
838 uint32_t instruction
= 0x10000000;
839 int64_t delta
= targetAddress
- instructionAddress
;
840 assert(delta
< 1024*1024);
841 assert(delta
> -1024*1024);
842 uint32_t immhi
= (delta
& 0x001FFFFC) << 3;
843 uint32_t immlo
= (delta
& 0x00000003) << 29;
844 return (instruction
| immhi
| immlo
| destReg
);
847 static uint32_t makeLoadOrStore(const LoadStoreInfo
& info
)
849 uint32_t instruction
= 0x39000000;
851 instruction
|= 0x04000000;
852 instruction
|= info
.reg
;
853 instruction
|= (info
.baseReg
<< 5);
854 uint32_t sizeBits
= 0;
855 uint32_t opcBits
= 0;
856 uint32_t imm12Bits
= 0;
857 switch ( info
.size
) {
860 imm12Bits
= info
.offset
;
861 if ( info
.isStore
) {
865 switch ( info
.signEx
) {
880 assert((info
.offset
% 2) == 0);
881 imm12Bits
= info
.offset
/2;
882 if ( info
.isStore
) {
886 switch ( info
.signEx
) {
901 assert((info
.offset
% 4) == 0);
902 imm12Bits
= info
.offset
/4;
903 if ( info
.isStore
) {
907 switch ( info
.signEx
) {
912 assert(0 && "cannot use signed32 with 32-bit load/store");
922 assert((info
.offset
% 8) == 0);
923 imm12Bits
= info
.offset
/8;
924 if ( info
.isStore
) {
929 assert(info
.signEx
== signedNot
);
934 assert((info
.offset
% 16) == 0);
935 imm12Bits
= info
.offset
/16;
936 assert(info
.isFloat
);
937 if ( info
.isStore
) {
945 assert(0 && "bad load/store size");
948 assert(imm12Bits
< 4096);
949 return (instruction
| (sizeBits
<< 30) | (opcBits
<< 22) | (imm12Bits
<< 10));
952 static bool parseLoadOrStore(uint32_t instruction
, LoadStoreInfo
& info
)
954 if ( (instruction
& 0x3B000000) != 0x39000000 )
956 info
.isFloat
= ( (instruction
& 0x04000000) != 0 );
957 info
.reg
= (instruction
& 0x1F);
958 info
.baseReg
= ((instruction
>>5) & 0x1F);
959 switch (instruction
& 0xC0C00000) {
963 info
.signEx
= signedNot
;
967 info
.isStore
= false;
968 info
.signEx
= signedNot
;
971 if ( info
.isFloat
) {
974 info
.signEx
= signedNot
;
978 info
.isStore
= false;
979 info
.signEx
= signed64
;
983 if ( info
.isFloat
) {
985 info
.isStore
= false;
986 info
.signEx
= signedNot
;
990 info
.isStore
= false;
991 info
.signEx
= signed32
;
997 info
.signEx
= signedNot
;
1001 info
.isStore
= false;
1002 info
.signEx
= signedNot
;
1006 info
.isStore
= false;
1007 info
.signEx
= signed64
;
1011 info
.isStore
= false;
1012 info
.signEx
= signed32
;
1016 info
.isStore
= true;
1017 info
.signEx
= signedNot
;
1021 info
.isStore
= false;
1022 info
.signEx
= signedNot
;
1026 info
.isStore
= false;
1027 info
.signEx
= signed64
;
1031 info
.isStore
= true;
1032 info
.signEx
= signedNot
;
1036 info
.isStore
= false;
1037 info
.signEx
= signedNot
;
1042 info
.offset
= ((instruction
>> 10) & 0x0FFF) * info
.size
;
1050 static bool parseADRP(uint32_t instruction
, AdrpInfo
& info
)
1052 if ( (instruction
& 0x9F000000) != 0x90000000 )
1054 info
.destReg
= (instruction
& 0x1F);
1064 static bool parseADD(uint32_t instruction
, AddInfo
& info
)
1066 if ( (instruction
& 0xFFC00000) != 0x91000000 )
1068 info
.destReg
= (instruction
& 0x1F);
1069 info
.srcReg
= ((instruction
>>5) & 0x1F);
1070 info
.addend
= ((instruction
>>10) & 0xFFF);
1077 static uint32_t makeLDR_scaledOffset(const LoadStoreInfo
& info
)
1079 assert((info
.reg
& 0xFFFFFFE0) == 0);
1080 assert((info
.baseReg
& 0xFFFFFFE0) == 0);
1081 assert(!info
.isFloat
|| (info
.signEx
!= signedNot
));
1082 uint32_t sizeBits
= 0;
1083 uint32_t opcBits
= 1;
1084 uint32_t vBit
= info
.isFloat
;
1085 switch ( info
.signEx
) {
1096 assert(0 && "bad SignExtension runtime value");
1098 switch ( info
.size
) {
1117 assert(0 && "invalid load size for literal");
1119 assert((info
.offset
% info
.size
) == 0);
1120 uint32_t scaledOffset
= info
.offset
/info
.size
;
1121 assert(scaledOffset
< 4096);
1122 return (0x39000000 | (sizeBits
<<30) | (vBit
<<26) | (opcBits
<<22) | (scaledOffset
<<10) | (info
.baseReg
<<5) | info
.reg
);
1125 static uint32_t makeLDR_literal(uint32_t destReg
, uint32_t loadSize
, bool isFloat
, uint64_t targetAddress
, uint64_t instructionAddress
)
1127 int64_t delta
= targetAddress
- instructionAddress
;
1128 assert(delta
< 1024*1024);
1129 assert(delta
> -1024*1024);
1130 assert((destReg
& 0xFFFFFFE0) == 0);
1131 assert((targetAddress
& 0x3) == 0);
1132 assert((instructionAddress
& 0x3) == 0);
1133 uint32_t imm19
= (delta
<< 3) & 0x00FFFFE0;
1134 uint32_t instruction
= 0;
1135 switch ( loadSize
) {
1137 instruction
= isFloat
? 0x1C000000 : 0x18000000;
1140 instruction
= isFloat
? 0x5C000000 : 0x58000000;
1143 instruction
= 0x9C000000;
1146 assert(0 && "invalid load size for literal");
1148 return (instruction
| imm19
| destReg
);
1152 static bool ldrInfo(uint32_t instruction
, uint8_t* size
, uint8_t* destReg
, bool* v
, uint32_t* scaledOffset
)
1154 *v
= ( (instruction
& 0x04000000) != 0 );
1155 *destReg
= (instruction
& 0x1F);
1156 uint32_t imm12
= ((instruction
>> 10) & 0x00000FFF);
1157 switch ( (instruction
& 0xC0000000) >> 30 ) {
1159 // vector and byte LDR have same "size" bits, need to check other bits to differenciate
1160 if ( (instruction
& 0x00800000) == 0 ) {
1162 *scaledOffset
= imm12
;
1166 *scaledOffset
= imm12
* 16;
1171 *scaledOffset
= imm12
* 2;
1175 *scaledOffset
= imm12
* 4;
1179 *scaledOffset
= imm12
* 8;
1182 return ((instruction
& 0x3B400000) == 0x39400000);
1186 static bool withinOneMeg(uint64_t addr1
, uint64_t addr2
) {
1187 int64_t delta
= (addr2
- addr1
);
1188 return ( (delta
< 1024*1024) && (delta
> -1024*1024) );
1191 void OutputFile::setInfo(ld::Internal
& state
, const ld::Atom
* atom
, uint8_t* buffer
, const std::map
<uint32_t, const Fixup
*>& usedByHints
,
1192 uint32_t offsetInAtom
, uint32_t delta
, InstructionInfo
* info
)
1194 info
->offsetInAtom
= offsetInAtom
+ delta
;
1195 std::map
<uint32_t, const Fixup
*>::const_iterator pos
= usedByHints
.find(info
->offsetInAtom
);
1196 if ( (pos
!= usedByHints
.end()) && (pos
->second
!= NULL
) ) {
1197 info
->fixup
= pos
->second
;
1198 info
->targetAddress
= addressOf(state
, info
->fixup
, &info
->target
);
1199 if ( info
->fixup
->clusterSize
!= ld::Fixup::k1of1
) {
1200 assert(info
->fixup
->firstInCluster());
1201 const ld::Fixup
* nextFixup
= info
->fixup
+ 1;
1202 if ( nextFixup
->kind
== ld::Fixup::kindAddAddend
) {
1203 info
->targetAddress
+= nextFixup
->u
.addend
;
1206 assert(0 && "expected addend");
1212 info
->targetAddress
= 0;
1213 info
->target
= NULL
;
1215 info
->instructionContent
= &buffer
[info
->offsetInAtom
];
1216 info
->instructionAddress
= atom
->finalAddress() + info
->offsetInAtom
;
1217 info
->instruction
= get32LE(info
->instructionContent
);
1220 static bool isPageKind(const ld::Fixup
* fixup
, bool mustBeGOT
=false)
1222 if ( fixup
== NULL
)
1225 switch ( fixup
->kind
) {
1226 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
1228 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
1229 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
1231 case ld::Fixup::kindSetTargetAddress
:
1235 } while ( ! f
->lastInCluster() );
1237 case ld::Fixup::kindStoreARM64Page21
:
1239 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
1240 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
1252 static bool isPageOffsetKind(const ld::Fixup
* fixup
, bool mustBeGOT
=false)
1254 if ( fixup
== NULL
)
1257 switch ( fixup
->kind
) {
1258 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
1260 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
1261 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
1263 case ld::Fixup::kindSetTargetAddress
:
1267 } while ( ! f
->lastInCluster() );
1269 case ld::Fixup::kindStoreARM64PageOff12
:
1271 case ld::Fixup::kindStoreARM64GOTLoadPageOff12
:
1272 case ld::Fixup::kindStoreARM64GOTLeaPageOff12
:
1285 #define LOH_ASSERT(cond) \
1287 warning("ignoring linker optimzation hint at %s+0x%X because " #cond, atom->name(), fit->offsetInAtom); \
1292 void OutputFile::applyFixUps(ld::Internal
& state
, uint64_t mhAddress
, const ld::Atom
* atom
, uint8_t* buffer
)
1294 //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
1295 int64_t accumulator
= 0;
1296 const ld::Atom
* toTarget
= NULL
;
1297 const ld::Atom
* fromTarget
;
1299 uint32_t instruction
;
1300 uint32_t newInstruction
;
1304 bool thumbTarget
= false;
1305 std::map
<uint32_t, const Fixup
*> usedByHints
;
1306 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
1307 uint8_t* fixUpLocation
= &buffer
[fit
->offsetInAtom
];
1308 ld::Fixup::LOH_arm64 lohExtra
;
1309 switch ( (ld::Fixup::Kind
)(fit
->kind
) ) {
1310 case ld::Fixup::kindNone
:
1311 case ld::Fixup::kindNoneFollowOn
:
1312 case ld::Fixup::kindNoneGroupSubordinate
:
1313 case ld::Fixup::kindNoneGroupSubordinateFDE
:
1314 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
1315 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
1317 case ld::Fixup::kindSetTargetAddress
:
1318 accumulator
= addressOf(state
, fit
, &toTarget
);
1319 thumbTarget
= targetIsThumb(state
, fit
);
1322 if ( fit
->contentAddendOnly
|| fit
->contentDetlaToAddendOnly
)
1325 case ld::Fixup::kindSubtractTargetAddress
:
1326 delta
= addressOf(state
, fit
, &fromTarget
);
1327 if ( ! fit
->contentAddendOnly
)
1328 accumulator
-= delta
;
1330 case ld::Fixup::kindAddAddend
:
1331 if ( ! fit
->contentIgnoresAddend
) {
1332 // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
1333 // into themselves such as jump tables. These .long should not have thumb bit set
1334 // even though the target is a thumb instruction. We can tell it is an interior pointer
1335 // because we are processing an addend.
1336 if ( thumbTarget
&& (toTarget
== atom
) && ((int32_t)fit
->u
.addend
> 0) ) {
1337 accumulator
&= (-2);
1338 //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X",
1339 // atom->section().sectionName(), atom->name(), fit->offsetInAtom);
1341 accumulator
+= fit
->u
.addend
;
1344 case ld::Fixup::kindSubtractAddend
:
1345 accumulator
-= fit
->u
.addend
;
1347 case ld::Fixup::kindSetTargetImageOffset
:
1348 accumulator
= addressOf(state
, fit
, &toTarget
) - mhAddress
;
1350 case ld::Fixup::kindSetTargetSectionOffset
:
1351 accumulator
= sectionOffsetOf(state
, fit
);
1353 case ld::Fixup::kindSetTargetTLVTemplateOffset
:
1354 accumulator
= tlvTemplateOffsetOf(state
, fit
);
1356 case ld::Fixup::kindStore8
:
1357 *fixUpLocation
+= accumulator
;
1359 case ld::Fixup::kindStoreLittleEndian16
:
1360 set16LE(fixUpLocation
, accumulator
);
1362 case ld::Fixup::kindStoreLittleEndianLow24of32
:
1363 set32LE(fixUpLocation
, (get32LE(fixUpLocation
) & 0xFF000000) | (accumulator
& 0x00FFFFFF) );
1365 case ld::Fixup::kindStoreLittleEndian32
:
1366 rangeCheckAbsolute32(accumulator
, state
, atom
, fit
);
1367 set32LE(fixUpLocation
, accumulator
);
1369 case ld::Fixup::kindStoreLittleEndian64
:
1370 set64LE(fixUpLocation
, accumulator
);
1372 case ld::Fixup::kindStoreBigEndian16
:
1373 set16BE(fixUpLocation
, accumulator
);
1375 case ld::Fixup::kindStoreBigEndianLow24of32
:
1376 set32BE(fixUpLocation
, (get32BE(fixUpLocation
) & 0xFF000000) | (accumulator
& 0x00FFFFFF) );
1378 case ld::Fixup::kindStoreBigEndian32
:
1379 rangeCheckAbsolute32(accumulator
, state
, atom
, fit
);
1380 set32BE(fixUpLocation
, accumulator
);
1382 case ld::Fixup::kindStoreBigEndian64
:
1383 set64BE(fixUpLocation
, accumulator
);
1385 case ld::Fixup::kindStoreX86PCRel8
:
1386 case ld::Fixup::kindStoreX86BranchPCRel8
:
1387 if ( fit
->contentAddendOnly
)
1388 delta
= accumulator
;
1390 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 1);
1391 rangeCheck8(delta
, state
, atom
, fit
);
1392 *fixUpLocation
= delta
;
1394 case ld::Fixup::kindStoreX86PCRel16
:
1395 if ( fit
->contentAddendOnly
)
1396 delta
= accumulator
;
1398 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 2);
1399 rangeCheck16(delta
, state
, atom
, fit
);
1400 set16LE(fixUpLocation
, delta
);
1402 case ld::Fixup::kindStoreX86BranchPCRel32
:
1403 if ( fit
->contentAddendOnly
)
1404 delta
= accumulator
;
1406 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1407 rangeCheckBranch32(delta
, state
, atom
, fit
);
1408 set32LE(fixUpLocation
, delta
);
1410 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
1411 case ld::Fixup::kindStoreX86PCRel32GOT
:
1412 case ld::Fixup::kindStoreX86PCRel32
:
1413 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
1414 if ( fit
->contentAddendOnly
)
1415 delta
= accumulator
;
1417 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1418 rangeCheckRIP32(delta
, state
, atom
, fit
);
1419 set32LE(fixUpLocation
, delta
);
1421 case ld::Fixup::kindStoreX86PCRel32_1
:
1422 if ( fit
->contentAddendOnly
)
1423 delta
= accumulator
- 1;
1425 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 5);
1426 rangeCheckRIP32(delta
, state
, atom
, fit
);
1427 set32LE(fixUpLocation
, delta
);
1429 case ld::Fixup::kindStoreX86PCRel32_2
:
1430 if ( fit
->contentAddendOnly
)
1431 delta
= accumulator
- 2;
1433 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 6);
1434 rangeCheckRIP32(delta
, state
, atom
, fit
);
1435 set32LE(fixUpLocation
, delta
);
1437 case ld::Fixup::kindStoreX86PCRel32_4
:
1438 if ( fit
->contentAddendOnly
)
1439 delta
= accumulator
- 4;
1441 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 8);
1442 rangeCheckRIP32(delta
, state
, atom
, fit
);
1443 set32LE(fixUpLocation
, delta
);
1445 case ld::Fixup::kindStoreX86Abs32TLVLoad
:
1446 set32LE(fixUpLocation
, accumulator
);
1448 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA
:
1449 assert(_options
.outputKind() != Options::kObjectFile
);
1450 // TLV entry was optimized away, change movl instruction to a leal
1451 if ( fixUpLocation
[-1] != 0xA1 )
1452 throw "TLV load reloc does not point to a movl instruction";
1453 fixUpLocation
[-1] = 0xB8;
1454 set32LE(fixUpLocation
, accumulator
);
1456 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
1457 assert(_options
.outputKind() != Options::kObjectFile
);
1458 // GOT entry was optimized away, change movq instruction to a leaq
1459 if ( fixUpLocation
[-2] != 0x8B )
1460 throw "GOT load reloc does not point to a movq instruction";
1461 fixUpLocation
[-2] = 0x8D;
1462 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1463 rangeCheckRIP32(delta
, state
, atom
, fit
);
1464 set32LE(fixUpLocation
, delta
);
1466 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
1467 assert(_options
.outputKind() != Options::kObjectFile
);
1468 // TLV entry was optimized away, change movq instruction to a leaq
1469 if ( fixUpLocation
[-2] != 0x8B )
1470 throw "TLV load reloc does not point to a movq instruction";
1471 fixUpLocation
[-2] = 0x8D;
1472 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1473 rangeCheckRIP32(delta
, state
, atom
, fit
);
1474 set32LE(fixUpLocation
, delta
);
1476 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
1477 accumulator
= addressOf(state
, fit
, &toTarget
);
1478 // fall into kindStoreARMLoad12 case
1479 case ld::Fixup::kindStoreARMLoad12
:
1480 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 8);
1481 rangeCheckARM12(delta
, state
, atom
, fit
);
1482 instruction
= get32LE(fixUpLocation
);
1484 newInstruction
= instruction
& 0xFFFFF000;
1485 newInstruction
|= ((uint32_t)delta
& 0xFFF);
1488 newInstruction
= instruction
& 0xFF7FF000;
1489 newInstruction
|= ((uint32_t)(-delta
) & 0xFFF);
1491 set32LE(fixUpLocation
, newInstruction
);
1493 case ld::Fixup::kindDtraceExtra
:
1495 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
1496 if ( _options
.outputKind() != Options::kObjectFile
) {
1497 // change call site to a NOP
1498 fixUpLocation
[-1] = 0x90; // 1-byte nop
1499 fixUpLocation
[0] = 0x0F; // 4-byte nop
1500 fixUpLocation
[1] = 0x1F;
1501 fixUpLocation
[2] = 0x40;
1502 fixUpLocation
[3] = 0x00;
1505 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
1506 if ( _options
.outputKind() != Options::kObjectFile
) {
1507 // change call site to a clear eax
1508 fixUpLocation
[-1] = 0x33; // xorl eax,eax
1509 fixUpLocation
[0] = 0xC0;
1510 fixUpLocation
[1] = 0x90; // 1-byte nop
1511 fixUpLocation
[2] = 0x90; // 1-byte nop
1512 fixUpLocation
[3] = 0x90; // 1-byte nop
1515 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
1516 if ( _options
.outputKind() != Options::kObjectFile
) {
1517 // change call site to a NOP
1518 set32LE(fixUpLocation
, 0xE1A00000);
1521 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
1522 if ( _options
.outputKind() != Options::kObjectFile
) {
1523 // change call site to 'eor r0, r0, r0'
1524 set32LE(fixUpLocation
, 0xE0200000);
1527 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
1528 if ( _options
.outputKind() != Options::kObjectFile
) {
1529 // change 32-bit blx call site to two thumb NOPs
1530 set32LE(fixUpLocation
, 0x46C046C0);
1533 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
1534 if ( _options
.outputKind() != Options::kObjectFile
) {
1535 // change 32-bit blx call site to 'nop', 'eor r0, r0'
1536 set32LE(fixUpLocation
, 0x46C04040);
1539 case ld::Fixup::kindStoreARM64DtraceCallSiteNop
:
1540 if ( _options
.outputKind() != Options::kObjectFile
) {
1541 // change call site to a NOP
1542 set32LE(fixUpLocation
, 0xD503201F);
1545 case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear
:
1546 if ( _options
.outputKind() != Options::kObjectFile
) {
1547 // change call site to 'MOVZ X0,0'
1548 set32LE(fixUpLocation
, 0xD2800000);
1551 case ld::Fixup::kindLazyTarget
:
1552 case ld::Fixup::kindIslandTarget
:
1554 case ld::Fixup::kindSetLazyOffset
:
1555 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
1556 accumulator
= this->lazyBindingInfoOffsetForLazyPointerAddress(fit
->u
.target
->finalAddress());
1558 case ld::Fixup::kindDataInCodeStartData
:
1559 case ld::Fixup::kindDataInCodeStartJT8
:
1560 case ld::Fixup::kindDataInCodeStartJT16
:
1561 case ld::Fixup::kindDataInCodeStartJT32
:
1562 case ld::Fixup::kindDataInCodeStartJTA32
:
1563 case ld::Fixup::kindDataInCodeEnd
:
1565 case ld::Fixup::kindLinkerOptimizationHint
:
1566 // expand table of address/offsets used by hints
1567 lohExtra
.addend
= fit
->u
.addend
;
1568 usedByHints
[fit
->offsetInAtom
+ (lohExtra
.info
.delta1
<< 2)] = NULL
;
1569 if ( lohExtra
.info
.count
> 0 )
1570 usedByHints
[fit
->offsetInAtom
+ (lohExtra
.info
.delta2
<< 2)] = NULL
;
1571 if ( lohExtra
.info
.count
> 1 )
1572 usedByHints
[fit
->offsetInAtom
+ (lohExtra
.info
.delta3
<< 2)] = NULL
;
1573 if ( lohExtra
.info
.count
> 2 )
1574 usedByHints
[fit
->offsetInAtom
+ (lohExtra
.info
.delta4
<< 2)] = NULL
;
1576 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
1577 accumulator
= addressOf(state
, fit
, &toTarget
);
1578 thumbTarget
= targetIsThumb(state
, fit
);
1581 if ( fit
->contentAddendOnly
)
1583 rangeCheckAbsolute32(accumulator
, state
, atom
, fit
);
1584 set32LE(fixUpLocation
, accumulator
);
1586 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
1587 accumulator
= addressOf(state
, fit
, &toTarget
);
1588 if ( fit
->contentAddendOnly
)
1590 set64LE(fixUpLocation
, accumulator
);
1592 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
1593 accumulator
= addressOf(state
, fit
, &toTarget
);
1594 if ( fit
->contentAddendOnly
)
1596 set32BE(fixUpLocation
, accumulator
);
1598 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
1599 accumulator
= addressOf(state
, fit
, &toTarget
);
1600 if ( fit
->contentAddendOnly
)
1602 set64BE(fixUpLocation
, accumulator
);
1604 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32
:
1605 accumulator
= tlvTemplateOffsetOf(state
, fit
);
1606 set32LE(fixUpLocation
, accumulator
);
1608 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64
:
1609 accumulator
= tlvTemplateOffsetOf(state
, fit
);
1610 set64LE(fixUpLocation
, accumulator
);
1612 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
1613 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
1614 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
1615 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
1616 accumulator
= addressOf(state
, fit
, &toTarget
);
1617 if ( fit
->contentDetlaToAddendOnly
)
1619 if ( fit
->contentAddendOnly
)
1622 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1623 rangeCheckRIP32(delta
, state
, atom
, fit
);
1624 set32LE(fixUpLocation
, delta
);
1626 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
1627 set32LE(fixUpLocation
, accumulator
);
1629 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA
:
1630 // TLV entry was optimized away, change movl instruction to a leal
1631 if ( fixUpLocation
[-1] != 0xA1 )
1632 throw "TLV load reloc does not point to a movl <abs-address>,<reg> instruction";
1633 fixUpLocation
[-1] = 0xB8;
1634 accumulator
= addressOf(state
, fit
, &toTarget
);
1635 set32LE(fixUpLocation
, accumulator
);
1637 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
1638 // GOT entry was optimized away, change movq instruction to a leaq
1639 if ( fixUpLocation
[-2] != 0x8B )
1640 throw "GOT load reloc does not point to a movq instruction";
1641 fixUpLocation
[-2] = 0x8D;
1642 accumulator
= addressOf(state
, fit
, &toTarget
);
1643 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1644 rangeCheckRIP32(delta
, state
, atom
, fit
);
1645 set32LE(fixUpLocation
, delta
);
1647 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
1648 // TLV entry was optimized away, change movq instruction to a leaq
1649 if ( fixUpLocation
[-2] != 0x8B )
1650 throw "TLV load reloc does not point to a movq instruction";
1651 fixUpLocation
[-2] = 0x8D;
1652 accumulator
= addressOf(state
, fit
, &toTarget
);
1653 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1654 rangeCheckRIP32(delta
, state
, atom
, fit
);
1655 set32LE(fixUpLocation
, delta
);
1657 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
1658 accumulator
= addressOf(state
, fit
, &toTarget
);
1659 thumbTarget
= targetIsThumb(state
, fit
);
1660 if ( toTarget
->contentType() == ld::Atom::typeBranchIsland
) {
1661 // Branching to island. If ultimate target is in range, branch there directly.
1662 for (ld::Fixup::iterator islandfit
= toTarget
->fixupsBegin(), end
=toTarget
->fixupsEnd(); islandfit
!= end
; ++islandfit
) {
1663 if ( islandfit
->kind
== ld::Fixup::kindIslandTarget
) {
1664 const ld::Atom
* islandTarget
= NULL
;
1665 uint64_t islandTargetAddress
= addressOf(state
, islandfit
, &islandTarget
);
1666 delta
= islandTargetAddress
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1667 if ( checkArmBranch24Displacement(delta
) ) {
1668 toTarget
= islandTarget
;
1669 accumulator
= islandTargetAddress
;
1670 thumbTarget
= targetIsThumb(state
, islandfit
);
1678 if ( fit
->contentDetlaToAddendOnly
)
1680 // fall into kindStoreARMBranch24 case
1681 case ld::Fixup::kindStoreARMBranch24
:
1682 // The pc added will be +8 from the pc
1683 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 8);
1684 rangeCheckARMBranch24(delta
, state
, atom
, fit
);
1685 instruction
= get32LE(fixUpLocation
);
1686 // Make sure we are calling arm with bl, thumb with blx
1687 is_bl
= ((instruction
& 0xFF000000) == 0xEB000000);
1688 is_blx
= ((instruction
& 0xFE000000) == 0xFA000000);
1689 is_b
= !is_blx
&& ((instruction
& 0x0F000000) == 0x0A000000);
1690 if ( (is_bl
| is_blx
) && thumbTarget
) {
1691 uint32_t opcode
= 0xFA000000; // force to be blx
1692 uint32_t disp
= (uint32_t)(delta
>> 2) & 0x00FFFFFF;
1693 uint32_t h_bit
= (uint32_t)(delta
<< 23) & 0x01000000;
1694 newInstruction
= opcode
| h_bit
| disp
;
1696 else if ( (is_bl
| is_blx
) && !thumbTarget
) {
1697 uint32_t opcode
= 0xEB000000; // force to be bl
1698 uint32_t disp
= (uint32_t)(delta
>> 2) & 0x00FFFFFF;
1699 newInstruction
= opcode
| disp
;
1701 else if ( is_b
&& thumbTarget
) {
1702 if ( fit
->contentDetlaToAddendOnly
)
1703 newInstruction
= (instruction
& 0xFF000000) | ((uint32_t)(delta
>> 2) & 0x00FFFFFF);
1705 throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s",
1706 referenceTargetAtomName(state
, fit
), atom
->name());
1708 else if ( !is_bl
&& !is_blx
&& thumbTarget
) {
1709 throwf("don't know how to convert instruction %x referencing %s to thumb",
1710 instruction
, referenceTargetAtomName(state
, fit
));
1713 newInstruction
= (instruction
& 0xFF000000) | ((uint32_t)(delta
>> 2) & 0x00FFFFFF);
1715 set32LE(fixUpLocation
, newInstruction
);
1717 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
1718 accumulator
= addressOf(state
, fit
, &toTarget
);
1719 thumbTarget
= targetIsThumb(state
, fit
);
1720 if ( toTarget
->contentType() == ld::Atom::typeBranchIsland
) {
1721 // branching to island, so see if ultimate target is in range
1722 // and if so branch to ultimate target instead.
1723 for (ld::Fixup::iterator islandfit
= toTarget
->fixupsBegin(), end
=toTarget
->fixupsEnd(); islandfit
!= end
; ++islandfit
) {
1724 if ( islandfit
->kind
== ld::Fixup::kindIslandTarget
) {
1725 const ld::Atom
* islandTarget
= NULL
;
1726 uint64_t islandTargetAddress
= addressOf(state
, islandfit
, &islandTarget
);
1727 delta
= islandTargetAddress
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1728 if ( checkThumbBranch22Displacement(delta
) ) {
1729 toTarget
= islandTarget
;
1730 accumulator
= islandTargetAddress
;
1731 thumbTarget
= targetIsThumb(state
, islandfit
);
1739 if ( fit
->contentDetlaToAddendOnly
)
1741 // fall into kindStoreThumbBranch22 case
1742 case ld::Fixup::kindStoreThumbBranch22
:
1743 instruction
= get32LE(fixUpLocation
);
1744 is_bl
= ((instruction
& 0xD000F800) == 0xD000F000);
1745 is_blx
= ((instruction
& 0xD000F800) == 0xC000F000);
1746 is_b
= ((instruction
& 0xD000F800) == 0x9000F000);
1747 // If the target is not thumb, we will be generating a blx instruction
1748 // Since blx cannot have the low bit set, set bit[1] of the target to
1749 // bit[1] of the base address, so that the difference is a multiple of
1751 if ( !thumbTarget
&& !fit
->contentDetlaToAddendOnly
) {
1752 accumulator
&= -3ULL;
1753 accumulator
|= ((atom
->finalAddress() + fit
->offsetInAtom
) & 2LL);
1755 // The pc added will be +4 from the pc
1756 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
+ 4);
1757 rangeCheckThumbBranch22(delta
, state
, atom
, fit
);
1758 if ( _options
.preferSubArchitecture() && _options
.archSupportsThumb2() ) {
1759 // The instruction is really two instructions:
1760 // The lower 16 bits are the first instruction, which contains the high
1761 // 11 bits of the displacement.
1762 // The upper 16 bits are the second instruction, which contains the low
1763 // 11 bits of the displacement, as well as differentiating bl and blx.
1764 uint32_t s
= (uint32_t)(delta
>> 24) & 0x1;
1765 uint32_t i1
= (uint32_t)(delta
>> 23) & 0x1;
1766 uint32_t i2
= (uint32_t)(delta
>> 22) & 0x1;
1767 uint32_t imm10
= (uint32_t)(delta
>> 12) & 0x3FF;
1768 uint32_t imm11
= (uint32_t)(delta
>> 1) & 0x7FF;
1769 uint32_t j1
= (i1
== s
);
1770 uint32_t j2
= (i2
== s
);
1773 instruction
= 0xD000F000; // keep bl
1775 instruction
= 0xC000F000; // change to blx
1777 else if ( is_blx
) {
1779 instruction
= 0xD000F000; // change to bl
1781 instruction
= 0xC000F000; // keep blx
1784 instruction
= 0x9000F000; // keep b
1785 if ( !thumbTarget
&& !fit
->contentDetlaToAddendOnly
) {
1786 throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
1787 referenceTargetAtomName(state
, fit
), atom
->name());
1792 throwf("don't know how to convert branch instruction %x referencing %s to bx",
1793 instruction
, referenceTargetAtomName(state
, fit
));
1794 instruction
= 0x9000F000; // keep b
1796 uint32_t nextDisp
= (j1
<< 13) | (j2
<< 11) | imm11
;
1797 uint32_t firstDisp
= (s
<< 10) | imm10
;
1798 newInstruction
= instruction
| (nextDisp
<< 16) | firstDisp
;
1799 //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, instruction=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
1800 // s, j1, j2, imm10, imm11, instruction, firstDisp, nextDisp, newInstruction, delta, atom->name(), toTarget->name());
1801 set32LE(fixUpLocation
, newInstruction
);
1804 // The instruction is really two instructions:
1805 // The lower 16 bits are the first instruction, which contains the high
1806 // 11 bits of the displacement.
1807 // The upper 16 bits are the second instruction, which contains the low
1808 // 11 bits of the displacement, as well as differentiating bl and blx.
1809 uint32_t firstDisp
= (uint32_t)(delta
>> 12) & 0x7FF;
1810 uint32_t nextDisp
= (uint32_t)(delta
>> 1) & 0x7FF;
1811 if ( is_bl
&& !thumbTarget
) {
1812 instruction
= 0xE800F000;
1814 else if ( is_blx
&& thumbTarget
) {
1815 instruction
= 0xF800F000;
1818 instruction
= 0x9000F000; // keep b
1819 if ( !thumbTarget
&& !fit
->contentDetlaToAddendOnly
) {
1820 throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
1821 referenceTargetAtomName(state
, fit
), atom
->name());
1825 instruction
= instruction
& 0xF800F800;
1827 newInstruction
= instruction
| (nextDisp
<< 16) | firstDisp
;
1828 set32LE(fixUpLocation
, newInstruction
);
1831 case ld::Fixup::kindStoreARMLow16
:
1833 uint32_t imm4
= (accumulator
& 0x0000F000) >> 12;
1834 uint32_t imm12
= accumulator
& 0x00000FFF;
1835 instruction
= get32LE(fixUpLocation
);
1836 newInstruction
= (instruction
& 0xFFF0F000) | (imm4
<< 16) | imm12
;
1837 set32LE(fixUpLocation
, newInstruction
);
1840 case ld::Fixup::kindStoreARMHigh16
:
1842 uint32_t imm4
= (accumulator
& 0xF0000000) >> 28;
1843 uint32_t imm12
= (accumulator
& 0x0FFF0000) >> 16;
1844 instruction
= get32LE(fixUpLocation
);
1845 newInstruction
= (instruction
& 0xFFF0F000) | (imm4
<< 16) | imm12
;
1846 set32LE(fixUpLocation
, newInstruction
);
1849 case ld::Fixup::kindStoreThumbLow16
:
1851 uint32_t imm4
= (accumulator
& 0x0000F000) >> 12;
1852 uint32_t i
= (accumulator
& 0x00000800) >> 11;
1853 uint32_t imm3
= (accumulator
& 0x00000700) >> 8;
1854 uint32_t imm8
= accumulator
& 0x000000FF;
1855 instruction
= get32LE(fixUpLocation
);
1856 newInstruction
= (instruction
& 0x8F00FBF0) | imm4
| (i
<< 10) | (imm3
<< 28) | (imm8
<< 16);
1857 set32LE(fixUpLocation
, newInstruction
);
1860 case ld::Fixup::kindStoreThumbHigh16
:
1862 uint32_t imm4
= (accumulator
& 0xF0000000) >> 28;
1863 uint32_t i
= (accumulator
& 0x08000000) >> 27;
1864 uint32_t imm3
= (accumulator
& 0x07000000) >> 24;
1865 uint32_t imm8
= (accumulator
& 0x00FF0000) >> 16;
1866 instruction
= get32LE(fixUpLocation
);
1867 newInstruction
= (instruction
& 0x8F00FBF0) | imm4
| (i
<< 10) | (imm3
<< 28) | (imm8
<< 16);
1868 set32LE(fixUpLocation
, newInstruction
);
1871 #if SUPPORT_ARCH_arm64
1872 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
1873 accumulator
= addressOf(state
, fit
, &toTarget
);
1874 // fall into kindStoreARM64Branch26 case
1875 case ld::Fixup::kindStoreARM64Branch26
:
1876 if ( fit
->contentAddendOnly
)
1877 delta
= accumulator
;
1879 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
);
1880 rangeCheckARM64Branch26(delta
, state
, atom
, fit
);
1881 instruction
= get32LE(fixUpLocation
);
1882 newInstruction
= (instruction
& 0xFC000000) | ((uint32_t)(delta
>> 2) & 0x03FFFFFF);
1883 set32LE(fixUpLocation
, newInstruction
);
1885 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
1886 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
1887 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
1888 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21
:
1889 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21
:
1890 accumulator
= addressOf(state
, fit
, &toTarget
);
1891 // fall into kindStoreARM64Branch26 case
1892 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
1893 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
1894 case ld::Fixup::kindStoreARM64TLVPLoadPage21
:
1895 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21
:
1896 case ld::Fixup::kindStoreARM64Page21
:
1898 // the ADRP instruction adds the imm << 12 to the page that the pc is on
1899 if ( fit
->contentAddendOnly
)
1902 delta
= (accumulator
& (-4096)) - ((atom
->finalAddress() + fit
->offsetInAtom
) & (-4096));
1903 rangeCheckARM64Page21(delta
, state
, atom
, fit
);
1904 instruction
= get32LE(fixUpLocation
);
1905 uint32_t immhi
= (delta
>> 9) & (0x00FFFFE0);
1906 uint32_t immlo
= (delta
<< 17) & (0x60000000);
1907 newInstruction
= (instruction
& 0x9F00001F) | immlo
| immhi
;
1908 set32LE(fixUpLocation
, newInstruction
);
1911 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
1912 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
1913 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12
:
1914 accumulator
= addressOf(state
, fit
, &toTarget
);
1915 // fall into kindAddressARM64PageOff12 case
1916 case ld::Fixup::kindStoreARM64TLVPLoadPageOff12
:
1917 case ld::Fixup::kindStoreARM64GOTLoadPageOff12
:
1918 case ld::Fixup::kindStoreARM64PageOff12
:
1920 uint32_t offset
= accumulator
& 0x00000FFF;
1921 instruction
= get32LE(fixUpLocation
);
1922 // LDR/STR instruction have implicit scale factor, need to compensate for that
1923 if ( instruction
& 0x08000000 ) {
1924 uint32_t implictShift
= ((instruction
>> 30) & 0x3);
1925 switch ( implictShift
) {
1927 if ( (instruction
& 0x04800000) == 0x04800000 ) {
1928 // vector and byte LDR/STR have same "size" bits, need to check other bits to differenciate
1930 if ( (offset
& 0xF) != 0 ) {
1931 throwf("128-bit LDR/STR not 16-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
1932 atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fit
),
1933 addressOf(state
, fit
, &toTarget
));
1938 if ( (offset
& 0x1) != 0 ) {
1939 throwf("16-bit LDR/STR not 2-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
1940 atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fit
),
1941 addressOf(state
, fit
, &toTarget
));
1945 if ( (offset
& 0x3) != 0 ) {
1946 throwf("32-bit LDR/STR not 4-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
1947 atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fit
),
1948 addressOf(state
, fit
, &toTarget
));
1952 if ( (offset
& 0x7) != 0 ) {
1953 throwf("64-bit LDR/STR not 8-byte aligned: from %s (0x%08llX) to %s (0x%08llX)",
1954 atom
->name(), atom
->finalAddress(), referenceTargetAtomName(state
, fit
),
1955 addressOf(state
, fit
, &toTarget
));
1959 // compensate for implicit scale
1960 offset
>>= implictShift
;
1962 if ( fit
->contentAddendOnly
)
1964 uint32_t imm12
= offset
<< 10;
1965 newInstruction
= (instruction
& 0xFFC003FF) | imm12
;
1966 set32LE(fixUpLocation
, newInstruction
);
1969 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
1970 accumulator
= addressOf(state
, fit
, &toTarget
);
1971 // fall into kindStoreARM64GOTLoadPage21 case
1972 case ld::Fixup::kindStoreARM64GOTLeaPageOff12
:
1974 // GOT entry was optimized away, change LDR instruction to a ADD
1975 instruction
= get32LE(fixUpLocation
);
1976 if ( (instruction
& 0xFFC00000) != 0xF9400000 )
1977 throwf("GOT load reloc does not point to a LDR instruction in %s", atom
->name());
1978 uint32_t offset
= accumulator
& 0x00000FFF;
1979 uint32_t imm12
= offset
<< 10;
1980 newInstruction
= 0x91000000 | imm12
| (instruction
& 0x000003FF);
1981 set32LE(fixUpLocation
, newInstruction
);
1984 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12
:
1985 accumulator
= addressOf(state
, fit
, &toTarget
);
1986 // fall into kindStoreARM64TLVPLeaPageOff12 case
1987 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12
:
1989 // TLV thunk in same linkage unit, so LEA it directly, changing LDR instruction to a ADD
1990 instruction
= get32LE(fixUpLocation
);
1991 if ( (instruction
& 0xFFC00000) != 0xF9400000 )
1992 throwf("TLV load reloc does not point to a LDR instruction in %s", atom
->name());
1993 uint32_t offset
= accumulator
& 0x00000FFF;
1994 uint32_t imm12
= offset
<< 10;
1995 newInstruction
= 0x91000000 | imm12
| (instruction
& 0x000003FF);
1996 set32LE(fixUpLocation
, newInstruction
);
1999 case ld::Fixup::kindStoreARM64PointerToGOT
:
2000 set64LE(fixUpLocation
, accumulator
);
2002 case ld::Fixup::kindStoreARM64PCRelToGOT
:
2003 if ( fit
->contentAddendOnly
)
2004 delta
= accumulator
;
2006 delta
= accumulator
- (atom
->finalAddress() + fit
->offsetInAtom
);
2007 set32LE(fixUpLocation
, delta
);
2013 // after all fixups are done on atom, if there are potential optimizations, do those
2014 if ( (usedByHints
.size() != 0) && (_options
.outputKind() != Options::kObjectFile
) && !_options
.ignoreOptimizationHints() ) {
2015 // fill in second part of usedByHints map, so we can see the target of fixups that might be optimized
2016 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
2017 switch ( fit
->kind
) {
2018 case ld::Fixup::kindLinkerOptimizationHint
:
2019 case ld::Fixup::kindNoneFollowOn
:
2020 case ld::Fixup::kindNoneGroupSubordinate
:
2021 case ld::Fixup::kindNoneGroupSubordinateFDE
:
2022 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
2023 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
2026 if ( fit
->firstInCluster() ) {
2027 std::map
<uint32_t, const Fixup
*>::iterator pos
= usedByHints
.find(fit
->offsetInAtom
);
2028 if ( pos
!= usedByHints
.end() ) {
2029 assert(pos
->second
== NULL
&& "two fixups in same hint location");
2031 //fprintf(stderr, "setting %s usedByHints[0x%04X], kind = %d\n", atom->name(), fit->offsetInAtom, fit->kind);
2037 // apply hints pass 1
2038 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
2039 if ( fit
->kind
!= ld::Fixup::kindLinkerOptimizationHint
)
2041 InstructionInfo infoA
;
2042 InstructionInfo infoB
;
2043 InstructionInfo infoC
;
2044 InstructionInfo infoD
;
2045 LoadStoreInfo ldrInfoB
, ldrInfoC
;
2049 bool targetFourByteAligned
;
2050 bool literalableSize
, isADRP
, isADD
, isLDR
, isSTR
;
2051 //uint8_t loadSize, destReg;
2052 //uint32_t scaledOffset;
2054 ld::Fixup::LOH_arm64 alt
;
2055 alt
.addend
= fit
->u
.addend
;
2056 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta1
<< 2), &infoA
);
2057 if ( alt
.info
.count
> 0 )
2058 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta2
<< 2), &infoB
);
2059 if ( alt
.info
.count
> 1 )
2060 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta3
<< 2), &infoC
);
2061 if ( alt
.info
.count
> 2 )
2062 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta4
<< 2), &infoD
);
2064 switch ( alt
.info
.kind
) {
2065 case LOH_ARM64_ADRP_ADRP
:
2066 // processed in pass 2 beacuse some ADRP may have been removed
2068 case LOH_ARM64_ADRP_LDR
:
2069 LOH_ASSERT(alt
.info
.count
== 1);
2070 LOH_ASSERT(isPageKind(infoA
.fixup
));
2071 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
));
2072 LOH_ASSERT(infoA
.target
== infoB
.target
);
2073 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2074 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2075 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2077 isLDR
= parseLoadOrStore(infoB
.instruction
, ldrInfoB
);
2079 LOH_ASSERT(ldrInfoB
.baseReg
== adrpInfoA
.destReg
);
2080 LOH_ASSERT(ldrInfoB
.offset
== (infoA
.targetAddress
& 0x00000FFF));
2081 literalableSize
= ( (ldrInfoB
.size
!= 1) && (ldrInfoB
.size
!= 2) );
2082 targetFourByteAligned
= ( (infoA
.targetAddress
& 0x3) == 0 );
2083 if ( literalableSize
&& usableSegment
&& targetFourByteAligned
&& withinOneMeg(infoB
.instructionAddress
, infoA
.targetAddress
) ) {
2084 set32LE(infoA
.instructionContent
, makeNOP());
2085 set32LE(infoB
.instructionContent
, makeLDR_literal(ldrInfoB
, infoA
.targetAddress
, infoB
.instructionAddress
));
2086 if ( _options
.verboseOptimizationHints() )
2087 fprintf(stderr
, "adrp-ldr at 0x%08llX transformed to LDR literal\n", infoB
.instructionAddress
);
2090 if ( _options
.verboseOptimizationHints() )
2091 fprintf(stderr
, "adrp-ldr at 0x%08llX not transformed, isLDR=%d, literalableSize=%d, inRange=%d, usableSegment=%d, scaledOffset=%d\n",
2092 infoB
.instructionAddress
, isLDR
, literalableSize
, withinOneMeg(infoB
.instructionAddress
, infoA
.targetAddress
), usableSegment
, ldrInfoB
.offset
);
2095 case LOH_ARM64_ADRP_ADD_LDR
:
2096 LOH_ASSERT(alt
.info
.count
== 2);
2097 LOH_ASSERT(isPageKind(infoA
.fixup
));
2098 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
));
2099 LOH_ASSERT(infoC
.fixup
== NULL
);
2100 LOH_ASSERT(infoA
.target
== infoB
.target
);
2101 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2102 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2103 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2105 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2107 LOH_ASSERT(adrpInfoA
.destReg
== addInfoB
.srcReg
);
2108 isLDR
= parseLoadOrStore(infoC
.instruction
, ldrInfoC
);
2110 LOH_ASSERT(addInfoB
.destReg
== ldrInfoC
.baseReg
);
2111 targetFourByteAligned
= ( ((infoB
.targetAddress
+ldrInfoC
.offset
) & 0x3) == 0 );
2112 literalableSize
= ( (ldrInfoC
.size
!= 1) && (ldrInfoC
.size
!= 2) );
2113 if ( literalableSize
&& usableSegment
&& targetFourByteAligned
&& withinOneMeg(infoC
.instructionAddress
, infoA
.targetAddress
+ldrInfoC
.offset
) ) {
2114 // can do T1 transformation to LDR literal
2115 set32LE(infoA
.instructionContent
, makeNOP());
2116 set32LE(infoB
.instructionContent
, makeNOP());
2117 set32LE(infoC
.instructionContent
, makeLDR_literal(ldrInfoC
, infoA
.targetAddress
+ldrInfoC
.offset
, infoC
.instructionAddress
));
2118 if ( _options
.verboseOptimizationHints() ) {
2119 fprintf(stderr
, "adrp-add-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC
.instructionAddress
);
2122 else if ( usableSegment
&& withinOneMeg(infoA
.instructionAddress
, infoA
.targetAddress
+ldrInfoC
.offset
) ) {
2123 // can to T4 transformation and turn ADRP/ADD into ADR
2124 set32LE(infoA
.instructionContent
, makeADR(ldrInfoC
.baseReg
, infoA
.targetAddress
+ldrInfoC
.offset
, infoA
.instructionAddress
));
2125 set32LE(infoB
.instructionContent
, makeNOP());
2126 ldrInfoC
.offset
= 0; // offset is now in ADR instead of ADD or LDR
2127 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2128 set32LE(infoC
.instructionContent
, infoC
.instruction
& 0xFFC003FF);
2129 if ( _options
.verboseOptimizationHints() )
2130 fprintf(stderr
, "adrp-add-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoB
.instructionAddress
);
2132 else if ( ((infoB
.targetAddress
% ldrInfoC
.size
) == 0) && (ldrInfoC
.offset
== 0) ) {
2133 // can do T2 transformation by merging ADD into LD
2135 set32LE(infoB
.instructionContent
, makeNOP());
2136 ldrInfoC
.offset
+= addInfoB
.addend
;
2137 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2138 if ( _options
.verboseOptimizationHints() )
2139 fprintf(stderr
, "adrp-add-ldr at 0x%08llX T2 transformed to ADRP/LDR \n", infoC
.instructionAddress
);
2142 if ( _options
.verboseOptimizationHints() )
2143 fprintf(stderr
, "adrp-add-ldr at 0x%08llX could not be transformed, loadSize=%d, literalableSize=%d, inRange=%d, usableSegment=%d, targetFourByteAligned=%d, imm12=%d\n",
2144 infoC
.instructionAddress
, ldrInfoC
.size
, literalableSize
, withinOneMeg(infoC
.instructionAddress
, infoA
.targetAddress
+ldrInfoC
.offset
), usableSegment
, targetFourByteAligned
, ldrInfoC
.offset
);
2147 case LOH_ARM64_ADRP_ADD
:
2148 LOH_ASSERT(alt
.info
.count
== 1);
2149 LOH_ASSERT(isPageKind(infoA
.fixup
));
2150 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
));
2151 LOH_ASSERT(infoA
.target
== infoB
.target
);
2152 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2153 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2155 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2157 LOH_ASSERT(adrpInfoA
.destReg
== addInfoB
.srcReg
);
2158 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2159 if ( usableSegment
&& withinOneMeg(infoA
.targetAddress
, infoA
.instructionAddress
) ) {
2160 // can do T4 transformation and use ADR
2161 set32LE(infoA
.instructionContent
, makeADR(addInfoB
.destReg
, infoA
.targetAddress
, infoA
.instructionAddress
));
2162 set32LE(infoB
.instructionContent
, makeNOP());
2163 if ( _options
.verboseOptimizationHints() )
2164 fprintf(stderr
, "adrp-add at 0x%08llX transformed to ADR\n", infoB
.instructionAddress
);
2167 if ( _options
.verboseOptimizationHints() )
2168 fprintf(stderr
, "adrp-add at 0x%08llX not transformed, isAdd=%d, inRange=%d, usableSegment=%d\n",
2169 infoB
.instructionAddress
, isADD
, withinOneMeg(infoA
.targetAddress
, infoA
.instructionAddress
), usableSegment
);
2172 case LOH_ARM64_ADRP_LDR_GOT_LDR
:
2173 LOH_ASSERT(alt
.info
.count
== 2);
2174 LOH_ASSERT(isPageKind(infoA
.fixup
, true));
2175 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
, true));
2176 LOH_ASSERT(infoC
.fixup
== NULL
);
2177 LOH_ASSERT(infoA
.target
== infoB
.target
);
2178 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2179 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2181 isLDR
= parseLoadOrStore(infoC
.instruction
, ldrInfoC
);
2183 LOH_ASSERT(ldrInfoC
.offset
== 0);
2184 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2185 isLDR
= parseLoadOrStore(infoB
.instruction
, ldrInfoB
);
2187 // target of GOT is external
2188 LOH_ASSERT(ldrInfoB
.size
== 8);
2189 LOH_ASSERT(!ldrInfoB
.isFloat
);
2190 LOH_ASSERT(ldrInfoC
.baseReg
== ldrInfoB
.reg
);
2191 //fprintf(stderr, "infoA.target=%p, %s, infoA.targetAddress=0x%08llX\n", infoA.target, infoA.target->name(), infoA.targetAddress);
2192 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2193 targetFourByteAligned
= ( ((infoA
.targetAddress
) & 0x3) == 0 );
2194 if ( usableSegment
&& targetFourByteAligned
&& withinOneMeg(infoB
.instructionAddress
, infoA
.targetAddress
) ) {
2195 // can do T5 transform
2196 set32LE(infoA
.instructionContent
, makeNOP());
2197 set32LE(infoB
.instructionContent
, makeLDR_literal(ldrInfoB
, infoA
.targetAddress
, infoB
.instructionAddress
));
2198 if ( _options
.verboseOptimizationHints() ) {
2199 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX T5 transformed to LDR literal of GOT plus LDR\n", infoC
.instructionAddress
);
2203 if ( _options
.verboseOptimizationHints() )
2204 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX no optimization done\n", infoC
.instructionAddress
);
2208 // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
2209 LOH_ASSERT(addInfoB
.srcReg
== adrpInfoA
.destReg
);
2210 LOH_ASSERT(addInfoB
.destReg
== ldrInfoC
.baseReg
);
2211 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2212 targetFourByteAligned
= ( ((infoA
.targetAddress
) & 0x3) == 0 );
2213 literalableSize
= ( (ldrInfoC
.size
!= 1) && (ldrInfoC
.size
!= 2) );
2214 if ( usableSegment
&& literalableSize
&& targetFourByteAligned
&& withinOneMeg(infoC
.instructionAddress
, infoA
.targetAddress
) ) {
2215 // can do T1 transform
2216 set32LE(infoA
.instructionContent
, makeNOP());
2217 set32LE(infoB
.instructionContent
, makeNOP());
2218 set32LE(infoC
.instructionContent
, makeLDR_literal(ldrInfoC
, infoA
.targetAddress
, infoC
.instructionAddress
));
2219 if ( _options
.verboseOptimizationHints() )
2220 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC
.instructionAddress
);
2222 else if ( usableSegment
&& withinOneMeg(infoA
.instructionAddress
, infoA
.targetAddress
) ) {
2223 // can do T4 transform
2224 set32LE(infoA
.instructionContent
, makeADR(ldrInfoC
.baseReg
, infoA
.targetAddress
, infoA
.instructionAddress
));
2225 set32LE(infoB
.instructionContent
, makeNOP());
2226 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2227 if ( _options
.verboseOptimizationHints() ) {
2228 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoC
.instructionAddress
);
2231 else if ( (infoA
.targetAddress
% ldrInfoC
.size
) == 0 ) {
2232 // can do T2 transform
2233 set32LE(infoB
.instructionContent
, makeNOP());
2234 ldrInfoC
.baseReg
= adrpInfoA
.destReg
;
2235 ldrInfoC
.offset
= addInfoB
.addend
;
2236 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2237 if ( _options
.verboseOptimizationHints() ) {
2238 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADRP/NOP/LDR\n", infoC
.instructionAddress
);
2242 // T3 transform already done by ld::passes:got:doPass()
2243 if ( _options
.verboseOptimizationHints() ) {
2244 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX T3 transformed to ADRP/ADD/LDR\n", infoC
.instructionAddress
);
2249 if ( _options
.verboseOptimizationHints() )
2250 fprintf(stderr
, "adrp-ldr-got-ldr at 0x%08llX not ADD or LDR\n", infoC
.instructionAddress
);
2253 case LOH_ARM64_ADRP_ADD_STR
:
2254 LOH_ASSERT(alt
.info
.count
== 2);
2255 LOH_ASSERT(isPageKind(infoA
.fixup
));
2256 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
));
2257 LOH_ASSERT(infoC
.fixup
== NULL
);
2258 LOH_ASSERT(infoA
.target
== infoB
.target
);
2259 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2260 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2261 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2263 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2265 LOH_ASSERT(adrpInfoA
.destReg
== addInfoB
.srcReg
);
2266 isSTR
= (parseLoadOrStore(infoC
.instruction
, ldrInfoC
) && ldrInfoC
.isStore
);
2268 LOH_ASSERT(addInfoB
.destReg
== ldrInfoC
.baseReg
);
2269 if ( usableSegment
&& withinOneMeg(infoA
.instructionAddress
, infoA
.targetAddress
+ldrInfoC
.offset
) ) {
2270 // can to T4 transformation and turn ADRP/ADD into ADR
2271 set32LE(infoA
.instructionContent
, makeADR(ldrInfoC
.baseReg
, infoA
.targetAddress
+ldrInfoC
.offset
, infoA
.instructionAddress
));
2272 set32LE(infoB
.instructionContent
, makeNOP());
2273 ldrInfoC
.offset
= 0; // offset is now in ADR instead of ADD or LDR
2274 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2275 set32LE(infoC
.instructionContent
, infoC
.instruction
& 0xFFC003FF);
2276 if ( _options
.verboseOptimizationHints() )
2277 fprintf(stderr
, "adrp-add-str at 0x%08llX T4 transformed to ADR/STR\n", infoB
.instructionAddress
);
2279 else if ( ((infoB
.targetAddress
% ldrInfoC
.size
) == 0) && (ldrInfoC
.offset
== 0) ) {
2280 // can do T2 transformation by merging ADD into STR
2282 set32LE(infoB
.instructionContent
, makeNOP());
2283 ldrInfoC
.offset
+= addInfoB
.addend
;
2284 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2285 if ( _options
.verboseOptimizationHints() )
2286 fprintf(stderr
, "adrp-add-str at 0x%08llX T2 transformed to ADRP/STR \n", infoC
.instructionAddress
);
2289 if ( _options
.verboseOptimizationHints() )
2290 fprintf(stderr
, "adrp-add-str at 0x%08llX could not be transformed, loadSize=%d, inRange=%d, usableSegment=%d, imm12=%d\n",
2291 infoC
.instructionAddress
, ldrInfoC
.size
, withinOneMeg(infoC
.instructionAddress
, infoA
.targetAddress
+ldrInfoC
.offset
), usableSegment
, ldrInfoC
.offset
);
2294 case LOH_ARM64_ADRP_LDR_GOT_STR
:
2295 LOH_ASSERT(alt
.info
.count
== 2);
2296 LOH_ASSERT(isPageKind(infoA
.fixup
, true));
2297 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
, true));
2298 LOH_ASSERT(infoC
.fixup
== NULL
);
2299 LOH_ASSERT(infoA
.target
== infoB
.target
);
2300 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2301 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2303 isSTR
= (parseLoadOrStore(infoC
.instruction
, ldrInfoC
) && ldrInfoC
.isStore
);
2305 LOH_ASSERT(ldrInfoC
.offset
== 0);
2306 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2307 isLDR
= parseLoadOrStore(infoB
.instruction
, ldrInfoB
);
2309 // target of GOT is external
2310 LOH_ASSERT(ldrInfoB
.size
== 8);
2311 LOH_ASSERT(!ldrInfoB
.isFloat
);
2312 LOH_ASSERT(ldrInfoC
.baseReg
== ldrInfoB
.reg
);
2313 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2314 targetFourByteAligned
= ( ((infoA
.targetAddress
) & 0x3) == 0 );
2315 if ( usableSegment
&& targetFourByteAligned
&& withinOneMeg(infoB
.instructionAddress
, infoA
.targetAddress
) ) {
2316 // can do T5 transform
2317 set32LE(infoA
.instructionContent
, makeNOP());
2318 set32LE(infoB
.instructionContent
, makeLDR_literal(ldrInfoB
, infoA
.targetAddress
, infoB
.instructionAddress
));
2319 if ( _options
.verboseOptimizationHints() ) {
2320 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX T5 transformed to LDR literal of GOT plus STR\n", infoC
.instructionAddress
);
2324 if ( _options
.verboseOptimizationHints() )
2325 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX no optimization done\n", infoC
.instructionAddress
);
2329 // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
2330 LOH_ASSERT(addInfoB
.srcReg
== adrpInfoA
.destReg
);
2331 LOH_ASSERT(addInfoB
.destReg
== ldrInfoC
.baseReg
);
2332 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2333 targetFourByteAligned
= ( ((infoA
.targetAddress
) & 0x3) == 0 );
2334 literalableSize
= ( (ldrInfoC
.size
!= 1) && (ldrInfoC
.size
!= 2) );
2335 if ( usableSegment
&& withinOneMeg(infoA
.instructionAddress
, infoA
.targetAddress
) ) {
2336 // can do T4 transform
2337 set32LE(infoA
.instructionContent
, makeADR(ldrInfoC
.baseReg
, infoA
.targetAddress
, infoA
.instructionAddress
));
2338 set32LE(infoB
.instructionContent
, makeNOP());
2339 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2340 if ( _options
.verboseOptimizationHints() ) {
2341 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADR/STR\n", infoC
.instructionAddress
);
2344 else if ( ((infoA
.targetAddress
% ldrInfoC
.size
) == 0) && (ldrInfoC
.offset
== 0) ) {
2345 // can do T2 transform
2346 set32LE(infoB
.instructionContent
, makeNOP());
2347 ldrInfoC
.baseReg
= adrpInfoA
.destReg
;
2348 ldrInfoC
.offset
= addInfoB
.addend
;
2349 set32LE(infoC
.instructionContent
, makeLoadOrStore(ldrInfoC
));
2350 if ( _options
.verboseOptimizationHints() ) {
2351 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADRP/NOP/STR\n", infoC
.instructionAddress
);
2355 // T3 transform already done by ld::passes:got:doPass()
2356 if ( _options
.verboseOptimizationHints() ) {
2357 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX T3 transformed to ADRP/ADD/STR\n", infoC
.instructionAddress
);
2362 if ( _options
.verboseOptimizationHints() )
2363 fprintf(stderr
, "adrp-ldr-got-str at 0x%08llX not ADD or LDR\n", infoC
.instructionAddress
);
2366 case LOH_ARM64_ADRP_LDR_GOT
:
2367 LOH_ASSERT(alt
.info
.count
== 1);
2368 LOH_ASSERT(isPageKind(infoA
.fixup
, true));
2369 LOH_ASSERT(isPageOffsetKind(infoB
.fixup
, true));
2370 LOH_ASSERT(infoA
.target
== infoB
.target
);
2371 LOH_ASSERT(infoA
.targetAddress
== infoB
.targetAddress
);
2372 isADRP
= parseADRP(infoA
.instruction
, adrpInfoA
);
2373 isADD
= parseADD(infoB
.instruction
, addInfoB
);
2374 isLDR
= parseLoadOrStore(infoB
.instruction
, ldrInfoB
);
2375 usableSegment
= ( !_options
.sharedRegionEligible() || (strcmp(atom
->section().segmentName(), infoB
.target
->section().segmentName()) == 0) );
2378 if ( usableSegment
&& withinOneMeg(infoB
.instructionAddress
, infoA
.targetAddress
) ) {
2379 // can do T5 transform (LDR literal load of GOT)
2380 set32LE(infoA
.instructionContent
, makeNOP());
2381 set32LE(infoB
.instructionContent
, makeLDR_literal(ldrInfoB
, infoA
.targetAddress
, infoB
.instructionAddress
));
2382 if ( _options
.verboseOptimizationHints() ) {
2383 fprintf(stderr
, "adrp-ldr-got at 0x%08llX T5 transformed to NOP/LDR\n", infoC
.instructionAddress
);
2388 if ( usableSegment
&& withinOneMeg(infoA
.instructionAddress
, infoA
.targetAddress
) ) {
2389 // can do T4 transform (ADR to compute local address)
2390 set32LE(infoA
.instructionContent
, makeADR(addInfoB
.destReg
, infoA
.targetAddress
, infoA
.instructionAddress
));
2391 set32LE(infoB
.instructionContent
, makeNOP());
2392 if ( _options
.verboseOptimizationHints() ) {
2393 fprintf(stderr
, "adrp-ldr-got at 0x%08llX T4 transformed to ADR/STR\n", infoC
.instructionAddress
);
2398 if ( _options
.verboseOptimizationHints() )
2399 fprintf(stderr
, "adrp-ldr-got at 0x%08llX not LDR or ADD\n", infoB
.instructionAddress
);
2403 if ( _options
.verboseOptimizationHints() )
2404 fprintf(stderr
, "adrp-ldr-got at 0x%08llX not ADRP\n", infoA
.instructionAddress
);
2408 if ( _options
.verboseOptimizationHints() )
2409 fprintf(stderr
, "unknown hint kind %d alt.info.kind at 0x%08llX\n", alt
.info
.kind
, infoA
.instructionAddress
);
2413 // apply hints pass 2
2414 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
2415 if ( fit
->kind
!= ld::Fixup::kindLinkerOptimizationHint
)
2417 InstructionInfo infoA
;
2418 InstructionInfo infoB
;
2419 ld::Fixup::LOH_arm64 alt
;
2420 alt
.addend
= fit
->u
.addend
;
2421 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta1
<< 2), &infoA
);
2422 if ( alt
.info
.count
> 0 )
2423 setInfo(state
, atom
, buffer
, usedByHints
, fit
->offsetInAtom
, (alt
.info
.delta2
<< 2), &infoB
);
2425 switch ( alt
.info
.kind
) {
2426 case LOH_ARM64_ADRP_ADRP
:
2427 LOH_ASSERT(isPageKind(infoA
.fixup
));
2428 LOH_ASSERT(isPageKind(infoB
.fixup
));
2429 if ( (infoA
.instruction
& 0x9F000000) != 0x90000000 ) {
2430 if ( _options
.verboseOptimizationHints() )
2431 fprintf(stderr
, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoA
.instructionAddress
, infoA
.instruction
);
2435 if ( (infoB
.instruction
& 0x9F000000) != 0x90000000 ) {
2436 if ( _options
.verboseOptimizationHints() )
2437 fprintf(stderr
, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoB
.instructionAddress
, infoA
.instruction
);
2441 if ( (infoA
.targetAddress
& (-4096)) == (infoB
.targetAddress
& (-4096)) ) {
2442 set32LE(infoB
.instructionContent
, 0xD503201F);
2458 void OutputFile::copyNoOps(uint8_t* from
, uint8_t* to
, bool thumb
)
2460 switch ( _options
.architecture() ) {
2462 case CPU_TYPE_X86_64
:
2463 for (uint8_t* p
=from
; p
< to
; ++p
)
2468 for (uint8_t* p
=from
; p
< to
; p
+= 2)
2469 OSWriteLittleInt16((uint16_t*)p
, 0, 0x46c0);
2472 for (uint8_t* p
=from
; p
< to
; p
+= 4)
2473 OSWriteLittleInt32((uint32_t*)p
, 0, 0xe1a00000);
2477 for (uint8_t* p
=from
; p
< to
; ++p
)
2483 bool OutputFile::takesNoDiskSpace(const ld::Section
* sect
)
2485 switch ( sect
->type() ) {
2486 case ld::Section::typeZeroFill
:
2487 case ld::Section::typeTLVZeroFill
:
2488 return _options
.optimizeZeroFill();
2489 case ld::Section::typePageZero
:
2490 case ld::Section::typeStack
:
2491 case ld::Section::typeAbsoluteSymbols
:
2492 case ld::Section::typeTentativeDefs
:
2500 bool OutputFile::hasZeroForFileOffset(const ld::Section
* sect
)
2502 switch ( sect
->type() ) {
2503 case ld::Section::typeZeroFill
:
2504 case ld::Section::typeTLVZeroFill
:
2505 return _options
.optimizeZeroFill();
2506 case ld::Section::typePageZero
:
2507 case ld::Section::typeStack
:
2508 case ld::Section::typeTentativeDefs
:
2516 void OutputFile::writeAtoms(ld::Internal
& state
, uint8_t* wholeBuffer
)
2518 // have each atom write itself
2519 uint64_t fileOffsetOfEndOfLastAtom
= 0;
2520 uint64_t mhAddress
= 0;
2521 bool lastAtomUsesNoOps
= false;
2522 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
2523 ld::Internal::FinalSection
* sect
= *sit
;
2524 if ( sect
->type() == ld::Section::typeMachHeader
)
2525 mhAddress
= sect
->address
;
2526 if ( takesNoDiskSpace(sect
) )
2528 const bool sectionUsesNops
= (sect
->type() == ld::Section::typeCode
);
2529 //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
2530 std::vector
<const ld::Atom
*>& atoms
= sect
->atoms
;
2531 bool lastAtomWasThumb
= false;
2532 for (std::vector
<const ld::Atom
*>::iterator ait
= atoms
.begin(); ait
!= atoms
.end(); ++ait
) {
2533 const ld::Atom
* atom
= *ait
;
2534 if ( atom
->definition() == ld::Atom::definitionProxy
)
2537 uint64_t fileOffset
= atom
->finalAddress() - sect
->address
+ sect
->fileOffset
;
2538 // check for alignment padding between atoms
2539 if ( (fileOffset
!= fileOffsetOfEndOfLastAtom
) && lastAtomUsesNoOps
) {
2540 this->copyNoOps(&wholeBuffer
[fileOffsetOfEndOfLastAtom
], &wholeBuffer
[fileOffset
], lastAtomWasThumb
);
2542 // copy atom content
2543 atom
->copyRawContent(&wholeBuffer
[fileOffset
]);
2545 this->applyFixUps(state
, mhAddress
, atom
, &wholeBuffer
[fileOffset
]);
2546 fileOffsetOfEndOfLastAtom
= fileOffset
+atom
->size();
2547 lastAtomUsesNoOps
= sectionUsesNops
;
2548 lastAtomWasThumb
= atom
->isThumb();
2550 catch (const char* msg
) {
2551 if ( atom
->file() != NULL
)
2552 throwf("%s in '%s' from %s", msg
, atom
->name(), atom
->file()->path());
2554 throwf("%s in '%s'", msg
, atom
->name());
2559 if ( _options
.verboseOptimizationHints() ) {
2560 //fprintf(stderr, "ADRP optimized away: %d\n", sAdrpNA);
2561 //fprintf(stderr, "ADRPs changed to NOPs: %d\n", sAdrpNoped);
2562 //fprintf(stderr, "ADRPs unchanged: %d\n", sAdrpNotNoped);
2567 void OutputFile::computeContentUUID(ld::Internal
& state
, uint8_t* wholeBuffer
)
2569 const bool log
= false;
2570 if ( (_options
.outputKind() != Options::kObjectFile
) || state
.someObjectFileHasDwarf
) {
2571 uint8_t digest
[CC_MD5_DIGEST_LENGTH
];
2572 uint32_t stabsStringsOffsetStart
;
2573 uint32_t tabsStringsOffsetEnd
;
2574 uint32_t stabsOffsetStart
;
2575 uint32_t stabsOffsetEnd
;
2576 if ( _symbolTableAtom
->hasStabs(stabsStringsOffsetStart
, tabsStringsOffsetEnd
, stabsOffsetStart
, stabsOffsetEnd
) ) {
2577 // find two areas of file that are stabs info and should not contribute to checksum
2578 uint64_t stringPoolFileOffset
= 0;
2579 uint64_t symbolTableFileOffset
= 0;
2580 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
2581 ld::Internal::FinalSection
* sect
= *sit
;
2582 if ( sect
->type() == ld::Section::typeLinkEdit
) {
2583 if ( strcmp(sect
->sectionName(), "__string_pool") == 0 )
2584 stringPoolFileOffset
= sect
->fileOffset
;
2585 else if ( strcmp(sect
->sectionName(), "__symbol_table") == 0 )
2586 symbolTableFileOffset
= sect
->fileOffset
;
2589 uint64_t firstStabNlistFileOffset
= symbolTableFileOffset
+ stabsOffsetStart
;
2590 uint64_t lastStabNlistFileOffset
= symbolTableFileOffset
+ stabsOffsetEnd
;
2591 uint64_t firstStabStringFileOffset
= stringPoolFileOffset
+ stabsStringsOffsetStart
;
2592 uint64_t lastStabStringFileOffset
= stringPoolFileOffset
+ tabsStringsOffsetEnd
;
2593 if ( log
) fprintf(stderr
, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset
);
2594 if ( log
) fprintf(stderr
, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset
);
2595 if ( log
) fprintf(stderr
, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset
);
2596 if ( log
) fprintf(stderr
, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset
);
2597 assert(firstStabNlistFileOffset
<= firstStabStringFileOffset
);
2599 CC_MD5_CTX md5state
;
2600 CC_MD5_Init(&md5state
);
2601 // checksum everything up to first stabs nlist
2602 if ( log
) fprintf(stderr
, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset
);
2603 CC_MD5_Update(&md5state
, &wholeBuffer
[0], firstStabNlistFileOffset
);
2604 // checkusm everything after last stabs nlist and up to first stabs string
2605 if ( log
) fprintf(stderr
, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset
, firstStabStringFileOffset
);
2606 CC_MD5_Update(&md5state
, &wholeBuffer
[lastStabNlistFileOffset
], firstStabStringFileOffset
-lastStabNlistFileOffset
);
2607 // checksum everything after last stabs string to end of file
2608 if ( log
) fprintf(stderr
, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset
, _fileSize
);
2609 CC_MD5_Update(&md5state
, &wholeBuffer
[lastStabStringFileOffset
], _fileSize
-lastStabStringFileOffset
);
2610 CC_MD5_Final(digest
, &md5state
);
2611 if ( log
) fprintf(stderr
, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest
[0], digest
[1], digest
[2],
2612 digest
[3], digest
[4], digest
[5], digest
[6], digest
[7]);
2615 CC_MD5(wholeBuffer
, _fileSize
, digest
);
2617 // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
2618 digest
[6] = ( digest
[6] & 0x0F ) | ( 3 << 4 );
2619 digest
[8] = ( digest
[8] & 0x3F ) | 0x80;
2620 // update buffer with new UUID
2621 _headersAndLoadCommandAtom
->setUUID(digest
);
2622 _headersAndLoadCommandAtom
->recopyUUIDCommand();
2627 void OutputFile::writeOutputFile(ld::Internal
& state
)
2629 // for UNIX conformance, error if file exists and is not writable
2630 if ( (access(_options
.outputFilePath(), F_OK
) == 0) && (access(_options
.outputFilePath(), W_OK
) == -1) )
2631 throwf("can't write output file: %s", _options
.outputFilePath());
2633 mode_t permissions
= 0777;
2634 if ( _options
.outputKind() == Options::kObjectFile
)
2636 mode_t umask
= ::umask(0);
2637 ::umask(umask
); // put back the original umask
2638 permissions
&= ~umask
;
2639 // Calling unlink first assures the file is gone so that open creates it with correct permissions
2640 // It also handles the case where __options.outputFilePath() file is not writable but its directory is
2641 // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
2642 // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
2643 struct stat stat_buf
;
2644 bool outputIsRegularFile
= false;
2645 bool outputIsMappableFile
= false;
2646 if ( stat(_options
.outputFilePath(), &stat_buf
) != -1 ) {
2647 if (stat_buf
.st_mode
& S_IFREG
) {
2648 outputIsRegularFile
= true;
2649 // <rdar://problem/12264302> Don't use mmap on non-hfs volumes
2650 struct statfs fsInfo
;
2651 if ( statfs(_options
.outputFilePath(), &fsInfo
) != -1 ) {
2652 if ( strcmp(fsInfo
.f_fstypename
, "hfs") == 0) {
2653 (void)unlink(_options
.outputFilePath());
2654 outputIsMappableFile
= true;
2658 outputIsMappableFile
= false;
2662 outputIsRegularFile
= false;
2666 // special files (pipes, devices, etc) must already exist
2667 outputIsRegularFile
= true;
2668 // output file does not exist yet
2669 char dirPath
[PATH_MAX
];
2670 strcpy(dirPath
, _options
.outputFilePath());
2671 char* end
= strrchr(dirPath
, '/');
2672 if ( end
!= NULL
) {
2674 struct statfs fsInfo
;
2675 if ( statfs(dirPath
, &fsInfo
) != -1 ) {
2676 if ( strcmp(fsInfo
.f_fstypename
, "hfs") == 0) {
2677 outputIsMappableFile
= true;
2683 //fprintf(stderr, "outputIsMappableFile=%d, outputIsRegularFile=%d, path=%s\n", outputIsMappableFile, outputIsRegularFile, _options.outputFilePath());
2686 // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
2687 const char filenameTemplate
[] = ".ld_XXXXXX";
2688 char tmpOutput
[PATH_MAX
];
2689 uint8_t *wholeBuffer
;
2690 if ( outputIsRegularFile
&& outputIsMappableFile
) {
2691 strcpy(tmpOutput
, _options
.outputFilePath());
2692 // If the path is too long to add a suffix for a temporary name then
2693 // just fall back to using the output path.
2694 if (strlen(tmpOutput
)+strlen(filenameTemplate
) < PATH_MAX
) {
2695 strcat(tmpOutput
, filenameTemplate
);
2696 fd
= mkstemp(tmpOutput
);
2699 fd
= open(tmpOutput
, O_RDWR
|O_CREAT
, permissions
);
2702 throwf("can't open output file for writing '%s', errno=%d", tmpOutput
, errno
);
2703 if ( ftruncate(fd
, _fileSize
) == -1 ) {
2706 if ( err
== ENOSPC
)
2707 throwf("not enough disk space for writing '%s'", _options
.outputFilePath());
2709 throwf("can't grow file for writing '%s', errno=%d", _options
.outputFilePath(), err
);
2712 wholeBuffer
= (uint8_t *)mmap(NULL
, _fileSize
, PROT_WRITE
|PROT_READ
, MAP_SHARED
, fd
, 0);
2713 if ( wholeBuffer
== MAP_FAILED
)
2714 throwf("can't create buffer of %llu bytes for output", _fileSize
);
2717 if ( outputIsRegularFile
)
2718 fd
= open(_options
.outputFilePath(), O_RDWR
|O_CREAT
, permissions
);
2720 fd
= open(_options
.outputFilePath(), O_WRONLY
);
2722 throwf("can't open output file for writing: %s, errno=%d", _options
.outputFilePath(), errno
);
2723 // try to allocate buffer for entire output file content
2724 wholeBuffer
= (uint8_t*)calloc(_fileSize
, 1);
2725 if ( wholeBuffer
== NULL
)
2726 throwf("can't create buffer of %llu bytes for output", _fileSize
);
2729 if ( _options
.UUIDMode() == Options::kUUIDRandom
) {
2731 ::uuid_generate_random(bits
);
2732 _headersAndLoadCommandAtom
->setUUID(bits
);
2735 writeAtoms(state
, wholeBuffer
);
2738 if ( _options
.UUIDMode() == Options::kUUIDContent
)
2739 computeContentUUID(state
, wholeBuffer
);
2741 if ( outputIsRegularFile
&& outputIsMappableFile
) {
2742 if ( ::chmod(tmpOutput
, permissions
) == -1 ) {
2744 throwf("can't set permissions on output file: %s, errno=%d", tmpOutput
, errno
);
2746 if ( ::rename(tmpOutput
, _options
.outputFilePath()) == -1 && strcmp(tmpOutput
, _options
.outputFilePath()) != 0) {
2748 throwf("can't move output file in place, errno=%d", errno
);
2752 if ( ::write(fd
, wholeBuffer
, _fileSize
) == -1 ) {
2753 throwf("can't write to output file: %s, errno=%d", _options
.outputFilePath(), errno
);
2756 // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
2757 // NFS seems to pad the end of the file sometimes. Calling trunc seems to correct it...
2758 ::truncate(_options
.outputFilePath(), _fileSize
);
2762 struct AtomByNameSorter
2764 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
)
2766 return (strcmp(left
->name(), right
->name()) < 0);
2773 NotInSet(const std::set
<const ld::Atom
*>& theSet
) : _set(theSet
) {}
2775 bool operator()(const ld::Atom
* atom
) const {
2776 return ( _set
.count(atom
) == 0 );
2779 const std::set
<const ld::Atom
*>& _set
;
2783 void OutputFile::buildSymbolTable(ld::Internal
& state
)
2785 unsigned int machoSectionIndex
= 0;
2786 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
2787 ld::Internal::FinalSection
* sect
= *sit
;
2788 bool setMachoSectionIndex
= !sect
->isSectionHidden() && (sect
->type() != ld::Section::typeTentativeDefs
);
2789 if ( setMachoSectionIndex
)
2790 ++machoSectionIndex
;
2791 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
2792 const ld::Atom
* atom
= *ait
;
2793 if ( setMachoSectionIndex
)
2794 (const_cast<ld::Atom
*>(atom
))->setMachoSection(machoSectionIndex
);
2795 else if ( sect
->type() == ld::Section::typeMachHeader
)
2796 (const_cast<ld::Atom
*>(atom
))->setMachoSection(1); // __mh_execute_header is not in any section by needs n_sect==1
2797 else if ( sect
->type() == ld::Section::typeLastSection
)
2798 (const_cast<ld::Atom
*>(atom
))->setMachoSection(machoSectionIndex
); // use section index of previous section
2799 else if ( sect
->type() == ld::Section::typeFirstSection
)
2800 (const_cast<ld::Atom
*>(atom
))->setMachoSection(machoSectionIndex
+1); // use section index of next section
2802 // in -r mode, clarify symbolTableNotInFinalLinkedImages
2803 if ( _options
.outputKind() == Options::kObjectFile
) {
2804 if ( (_options
.architecture() == CPU_TYPE_X86_64
) || (_options
.architecture() == CPU_TYPE_ARM64
) ) {
2805 // x86_64 .o files need labels on anonymous literal strings
2806 if ( (sect
->type() == ld::Section::typeCString
) && (atom
->combine() == ld::Atom::combineByNameAndContent
) ) {
2807 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableIn
);
2808 _localAtoms
.push_back(atom
);
2812 if ( sect
->type() == ld::Section::typeCFI
) {
2813 if ( _options
.removeEHLabels() )
2814 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn
);
2816 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableIn
);
2818 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages
)
2819 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableIn
);
2822 // TEMP work around until <rdar://problem/7702923> goes in
2823 if ( (atom
->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip
)
2824 && (atom
->scope() == ld::Atom::scopeLinkageUnit
)
2825 && (_options
.outputKind() == Options::kDynamicLibrary
) ) {
2826 (const_cast<ld::Atom
*>(atom
))->setScope(ld::Atom::scopeGlobal
);
2829 // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
2830 if ( atom
->autoHide() && (_options
.outputKind() != Options::kObjectFile
) ) {
2831 // adding auto-hide symbol to .exp file should keep it global
2832 if ( !_options
.hasExportMaskList() || !_options
.shouldExport(atom
->name()) )
2833 (const_cast<ld::Atom
*>(atom
))->setScope(ld::Atom::scopeLinkageUnit
);
2836 // <rdar://problem/8626058> ld should consistently warn when resolvers are not exported
2837 if ( (atom
->contentType() == ld::Atom::typeResolver
) && (atom
->scope() == ld::Atom::scopeLinkageUnit
) )
2838 warning("resolver functions should be external, but '%s' is hidden", atom
->name());
2840 if ( sect
->type() == ld::Section::typeImportProxies
) {
2841 if ( atom
->combine() == ld::Atom::combineByName
)
2842 this->usesWeakExternalSymbols
= true;
2843 // alias proxy is a re-export with a name change, don't import changed name
2844 if ( ! atom
->isAlias() )
2845 _importedAtoms
.push_back(atom
);
2846 // scope of proxies are usually linkage unit, so done
2847 // if scope is global, we need to re-export it too
2848 if ( atom
->scope() == ld::Atom::scopeGlobal
)
2849 _exportedAtoms
.push_back(atom
);
2852 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages
) {
2853 assert(_options
.outputKind() != Options::kObjectFile
);
2854 continue; // don't add to symbol table
2856 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
) {
2857 continue; // don't add to symbol table
2859 if ( (atom
->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel
)
2860 && (_options
.outputKind() != Options::kObjectFile
) ) {
2861 continue; // don't add to symbol table
2864 if ( (atom
->definition() == ld::Atom::definitionTentative
) && (_options
.outputKind() == Options::kObjectFile
) ) {
2865 if ( _options
.makeTentativeDefinitionsReal() ) {
2866 // -r -d turns tentative defintions into real def
2867 _exportedAtoms
.push_back(atom
);
2870 // in mach-o object files tentative defintions are stored like undefined symbols
2871 _importedAtoms
.push_back(atom
);
2876 switch ( atom
->scope() ) {
2877 case ld::Atom::scopeTranslationUnit
:
2878 if ( _options
.keepLocalSymbol(atom
->name()) ) {
2879 _localAtoms
.push_back(atom
);
2882 if ( _options
.outputKind() == Options::kObjectFile
) {
2883 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel
);
2884 _localAtoms
.push_back(atom
);
2887 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn
);
2890 case ld::Atom::scopeGlobal
:
2891 _exportedAtoms
.push_back(atom
);
2893 case ld::Atom::scopeLinkageUnit
:
2894 if ( _options
.outputKind() == Options::kObjectFile
) {
2895 if ( _options
.keepPrivateExterns() ) {
2896 _exportedAtoms
.push_back(atom
);
2898 else if ( _options
.keepLocalSymbol(atom
->name()) ) {
2899 _localAtoms
.push_back(atom
);
2902 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel
);
2903 _localAtoms
.push_back(atom
);
2907 if ( _options
.keepLocalSymbol(atom
->name()) )
2908 _localAtoms
.push_back(atom
);
2909 // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
2910 // this works by making __mh_execute_header be a local symbol which takes symbol index 0
2911 else if ( (atom
->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip
) && !_options
.makeCompressedDyldInfo() )
2912 _localAtoms
.push_back(atom
);
2914 (const_cast<ld::Atom
*>(atom
))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn
);
2921 // <rdar://problem/6978069> ld adds undefined symbol from .exp file to binary
2922 if ( (_options
.outputKind() == Options::kKextBundle
) && _options
.hasExportRestrictList() ) {
2923 // search for referenced undefines
2924 std::set
<const ld::Atom
*> referencedProxyAtoms
;
2925 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
2926 ld::Internal::FinalSection
* sect
= *sit
;
2927 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
2928 const ld::Atom
* atom
= *ait
;
2929 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
2930 switch ( fit
->binding
) {
2931 case ld::Fixup::bindingsIndirectlyBound
:
2932 referencedProxyAtoms
.insert(state
.indirectBindingTable
[fit
->u
.bindingIndex
]);
2934 case ld::Fixup::bindingDirectlyBound
:
2935 referencedProxyAtoms
.insert(fit
->u
.target
);
2943 // remove any unreferenced _importedAtoms
2944 _importedAtoms
.erase(std::remove_if(_importedAtoms
.begin(), _importedAtoms
.end(), NotInSet(referencedProxyAtoms
)), _importedAtoms
.end());
2948 std::sort(_exportedAtoms
.begin(), _exportedAtoms
.end(), AtomByNameSorter());
2949 std::sort(_importedAtoms
.begin(), _importedAtoms
.end(), AtomByNameSorter());
2952 void OutputFile::addPreloadLinkEdit(ld::Internal
& state
)
2954 switch ( _options
.architecture() ) {
2955 #if SUPPORT_ARCH_i386
2957 if ( _hasLocalRelocations
) {
2958 _localRelocsAtom
= new LocalRelocationsAtom
<x86
>(_options
, state
, *this);
2959 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
2961 if ( _hasExternalRelocations
) {
2962 _externalRelocsAtom
= new ExternalRelocationsAtom
<x86
>(_options
, state
, *this);
2963 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
2965 if ( _hasSymbolTable
) {
2966 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<x86
>(_options
, state
, *this);
2967 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
2968 _symbolTableAtom
= new SymbolTableAtom
<x86
>(_options
, state
, *this);
2969 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
2970 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
2971 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
2975 #if SUPPORT_ARCH_x86_64
2976 case CPU_TYPE_X86_64
:
2977 if ( _hasLocalRelocations
) {
2978 _localRelocsAtom
= new LocalRelocationsAtom
<x86_64
>(_options
, state
, *this);
2979 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
2981 if ( _hasExternalRelocations
) {
2982 _externalRelocsAtom
= new ExternalRelocationsAtom
<x86_64
>(_options
, state
, *this);
2983 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
2985 if ( _hasSymbolTable
) {
2986 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<x86_64
>(_options
, state
, *this);
2987 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
2988 _symbolTableAtom
= new SymbolTableAtom
<x86_64
>(_options
, state
, *this);
2989 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
2990 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
2991 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
2995 #if SUPPORT_ARCH_arm_any
2997 if ( _hasLocalRelocations
) {
2998 _localRelocsAtom
= new LocalRelocationsAtom
<arm
>(_options
, state
, *this);
2999 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3001 if ( _hasExternalRelocations
) {
3002 _externalRelocsAtom
= new ExternalRelocationsAtom
<arm
>(_options
, state
, *this);
3003 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3005 if ( _hasSymbolTable
) {
3006 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<arm
>(_options
, state
, *this);
3007 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3008 _symbolTableAtom
= new SymbolTableAtom
<arm
>(_options
, state
, *this);
3009 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3010 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
3011 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3015 #if SUPPORT_ARCH_arm64
3016 case CPU_TYPE_ARM64
:
3017 if ( _hasLocalRelocations
) {
3018 _localRelocsAtom
= new LocalRelocationsAtom
<arm64
>(_options
, state
, *this);
3019 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3021 if ( _hasExternalRelocations
) {
3022 _externalRelocsAtom
= new ExternalRelocationsAtom
<arm64
>(_options
, state
, *this);
3023 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3025 if ( _hasSymbolTable
) {
3026 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<arm64
>(_options
, state
, *this);
3027 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3028 _symbolTableAtom
= new SymbolTableAtom
<arm64
>(_options
, state
, *this);
3029 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3030 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
3031 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3036 throw "-preload not supported";
3042 void OutputFile::addLinkEdit(ld::Internal
& state
)
3044 // for historical reasons, -preload orders LINKEDIT content differently
3045 if ( _options
.outputKind() == Options::kPreload
)
3046 return addPreloadLinkEdit(state
);
3048 switch ( _options
.architecture() ) {
3049 #if SUPPORT_ARCH_i386
3051 if ( _hasSectionRelocations
) {
3052 _sectionsRelocationsAtom
= new SectionRelocationsAtom
<x86
>(_options
, state
, *this);
3053 sectionRelocationsSection
= state
.addAtom(*_sectionsRelocationsAtom
);
3055 if ( _hasDyldInfo
) {
3056 _rebasingInfoAtom
= new RebaseInfoAtom
<x86
>(_options
, state
, *this);
3057 rebaseSection
= state
.addAtom(*_rebasingInfoAtom
);
3059 _bindingInfoAtom
= new BindingInfoAtom
<x86
>(_options
, state
, *this);
3060 bindingSection
= state
.addAtom(*_bindingInfoAtom
);
3062 _weakBindingInfoAtom
= new WeakBindingInfoAtom
<x86
>(_options
, state
, *this);
3063 weakBindingSection
= state
.addAtom(*_weakBindingInfoAtom
);
3065 _lazyBindingInfoAtom
= new LazyBindingInfoAtom
<x86
>(_options
, state
, *this);
3066 lazyBindingSection
= state
.addAtom(*_lazyBindingInfoAtom
);
3068 _exportInfoAtom
= new ExportInfoAtom
<x86
>(_options
, state
, *this);
3069 exportSection
= state
.addAtom(*_exportInfoAtom
);
3071 if ( _hasLocalRelocations
) {
3072 _localRelocsAtom
= new LocalRelocationsAtom
<x86
>(_options
, state
, *this);
3073 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3075 if ( _hasSplitSegInfo
) {
3076 _splitSegInfoAtom
= new SplitSegInfoAtom
<x86
>(_options
, state
, *this);
3077 splitSegInfoSection
= state
.addAtom(*_splitSegInfoAtom
);
3079 if ( _hasFunctionStartsInfo
) {
3080 _functionStartsAtom
= new FunctionStartsAtom
<x86
>(_options
, state
, *this);
3081 functionStartsSection
= state
.addAtom(*_functionStartsAtom
);
3083 if ( _hasDataInCodeInfo
) {
3084 _dataInCodeAtom
= new DataInCodeAtom
<x86
>(_options
, state
, *this);
3085 dataInCodeSection
= state
.addAtom(*_dataInCodeAtom
);
3087 if ( _hasOptimizationHints
) {
3088 _optimizationHintsAtom
= new OptimizationHintsAtom
<x86
>(_options
, state
, *this);
3089 optimizationHintsSection
= state
.addAtom(*_optimizationHintsAtom
);
3091 if ( _hasDependentDRInfo
) {
3092 _dependentDRInfoAtom
= new DependentDRAtom
<x86
>(_options
, state
, *this);
3093 dependentDRsSection
= state
.addAtom(*_dependentDRInfoAtom
);
3095 if ( _hasSymbolTable
) {
3096 _symbolTableAtom
= new SymbolTableAtom
<x86
>(_options
, state
, *this);
3097 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3099 if ( _hasExternalRelocations
) {
3100 _externalRelocsAtom
= new ExternalRelocationsAtom
<x86
>(_options
, state
, *this);
3101 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3103 if ( _hasSymbolTable
) {
3104 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<x86
>(_options
, state
, *this);
3105 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3106 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
3107 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3111 #if SUPPORT_ARCH_x86_64
3112 case CPU_TYPE_X86_64
:
3113 if ( _hasSectionRelocations
) {
3114 _sectionsRelocationsAtom
= new SectionRelocationsAtom
<x86_64
>(_options
, state
, *this);
3115 sectionRelocationsSection
= state
.addAtom(*_sectionsRelocationsAtom
);
3117 if ( _hasDyldInfo
) {
3118 _rebasingInfoAtom
= new RebaseInfoAtom
<x86_64
>(_options
, state
, *this);
3119 rebaseSection
= state
.addAtom(*_rebasingInfoAtom
);
3121 _bindingInfoAtom
= new BindingInfoAtom
<x86_64
>(_options
, state
, *this);
3122 bindingSection
= state
.addAtom(*_bindingInfoAtom
);
3124 _weakBindingInfoAtom
= new WeakBindingInfoAtom
<x86_64
>(_options
, state
, *this);
3125 weakBindingSection
= state
.addAtom(*_weakBindingInfoAtom
);
3127 _lazyBindingInfoAtom
= new LazyBindingInfoAtom
<x86_64
>(_options
, state
, *this);
3128 lazyBindingSection
= state
.addAtom(*_lazyBindingInfoAtom
);
3130 _exportInfoAtom
= new ExportInfoAtom
<x86_64
>(_options
, state
, *this);
3131 exportSection
= state
.addAtom(*_exportInfoAtom
);
3133 if ( _hasLocalRelocations
) {
3134 _localRelocsAtom
= new LocalRelocationsAtom
<x86_64
>(_options
, state
, *this);
3135 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3137 if ( _hasSplitSegInfo
) {
3138 _splitSegInfoAtom
= new SplitSegInfoAtom
<x86_64
>(_options
, state
, *this);
3139 splitSegInfoSection
= state
.addAtom(*_splitSegInfoAtom
);
3141 if ( _hasFunctionStartsInfo
) {
3142 _functionStartsAtom
= new FunctionStartsAtom
<x86_64
>(_options
, state
, *this);
3143 functionStartsSection
= state
.addAtom(*_functionStartsAtom
);
3145 if ( _hasDataInCodeInfo
) {
3146 _dataInCodeAtom
= new DataInCodeAtom
<x86_64
>(_options
, state
, *this);
3147 dataInCodeSection
= state
.addAtom(*_dataInCodeAtom
);
3149 if ( _hasOptimizationHints
) {
3150 _optimizationHintsAtom
= new OptimizationHintsAtom
<x86_64
>(_options
, state
, *this);
3151 optimizationHintsSection
= state
.addAtom(*_optimizationHintsAtom
);
3153 if ( _hasDependentDRInfo
) {
3154 _dependentDRInfoAtom
= new DependentDRAtom
<x86_64
>(_options
, state
, *this);
3155 dependentDRsSection
= state
.addAtom(*_dependentDRInfoAtom
);
3157 if ( _hasSymbolTable
) {
3158 _symbolTableAtom
= new SymbolTableAtom
<x86_64
>(_options
, state
, *this);
3159 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3161 if ( _hasExternalRelocations
) {
3162 _externalRelocsAtom
= new ExternalRelocationsAtom
<x86_64
>(_options
, state
, *this);
3163 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3165 if ( _hasSymbolTable
) {
3166 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<x86_64
>(_options
, state
, *this);
3167 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3168 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 8);
3169 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3173 #if SUPPORT_ARCH_arm_any
3175 if ( _hasSectionRelocations
) {
3176 _sectionsRelocationsAtom
= new SectionRelocationsAtom
<arm
>(_options
, state
, *this);
3177 sectionRelocationsSection
= state
.addAtom(*_sectionsRelocationsAtom
);
3179 if ( _hasDyldInfo
) {
3180 _rebasingInfoAtom
= new RebaseInfoAtom
<arm
>(_options
, state
, *this);
3181 rebaseSection
= state
.addAtom(*_rebasingInfoAtom
);
3183 _bindingInfoAtom
= new BindingInfoAtom
<arm
>(_options
, state
, *this);
3184 bindingSection
= state
.addAtom(*_bindingInfoAtom
);
3186 _weakBindingInfoAtom
= new WeakBindingInfoAtom
<arm
>(_options
, state
, *this);
3187 weakBindingSection
= state
.addAtom(*_weakBindingInfoAtom
);
3189 _lazyBindingInfoAtom
= new LazyBindingInfoAtom
<arm
>(_options
, state
, *this);
3190 lazyBindingSection
= state
.addAtom(*_lazyBindingInfoAtom
);
3192 _exportInfoAtom
= new ExportInfoAtom
<arm
>(_options
, state
, *this);
3193 exportSection
= state
.addAtom(*_exportInfoAtom
);
3195 if ( _hasLocalRelocations
) {
3196 _localRelocsAtom
= new LocalRelocationsAtom
<arm
>(_options
, state
, *this);
3197 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3199 if ( _hasSplitSegInfo
) {
3200 _splitSegInfoAtom
= new SplitSegInfoAtom
<arm
>(_options
, state
, *this);
3201 splitSegInfoSection
= state
.addAtom(*_splitSegInfoAtom
);
3203 if ( _hasFunctionStartsInfo
) {
3204 _functionStartsAtom
= new FunctionStartsAtom
<arm
>(_options
, state
, *this);
3205 functionStartsSection
= state
.addAtom(*_functionStartsAtom
);
3207 if ( _hasDataInCodeInfo
) {
3208 _dataInCodeAtom
= new DataInCodeAtom
<arm
>(_options
, state
, *this);
3209 dataInCodeSection
= state
.addAtom(*_dataInCodeAtom
);
3211 if ( _hasOptimizationHints
) {
3212 _optimizationHintsAtom
= new OptimizationHintsAtom
<arm
>(_options
, state
, *this);
3213 optimizationHintsSection
= state
.addAtom(*_optimizationHintsAtom
);
3215 if ( _hasDependentDRInfo
) {
3216 _dependentDRInfoAtom
= new DependentDRAtom
<arm
>(_options
, state
, *this);
3217 dependentDRsSection
= state
.addAtom(*_dependentDRInfoAtom
);
3219 if ( _hasSymbolTable
) {
3220 _symbolTableAtom
= new SymbolTableAtom
<arm
>(_options
, state
, *this);
3221 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3223 if ( _hasExternalRelocations
) {
3224 _externalRelocsAtom
= new ExternalRelocationsAtom
<arm
>(_options
, state
, *this);
3225 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3227 if ( _hasSymbolTable
) {
3228 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<arm
>(_options
, state
, *this);
3229 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3230 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
3231 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3235 #if SUPPORT_ARCH_arm64
3236 case CPU_TYPE_ARM64
:
3237 if ( _hasSectionRelocations
) {
3238 _sectionsRelocationsAtom
= new SectionRelocationsAtom
<arm64
>(_options
, state
, *this);
3239 sectionRelocationsSection
= state
.addAtom(*_sectionsRelocationsAtom
);
3241 if ( _hasDyldInfo
) {
3242 _rebasingInfoAtom
= new RebaseInfoAtom
<arm64
>(_options
, state
, *this);
3243 rebaseSection
= state
.addAtom(*_rebasingInfoAtom
);
3245 _bindingInfoAtom
= new BindingInfoAtom
<arm64
>(_options
, state
, *this);
3246 bindingSection
= state
.addAtom(*_bindingInfoAtom
);
3248 _weakBindingInfoAtom
= new WeakBindingInfoAtom
<arm64
>(_options
, state
, *this);
3249 weakBindingSection
= state
.addAtom(*_weakBindingInfoAtom
);
3251 _lazyBindingInfoAtom
= new LazyBindingInfoAtom
<arm64
>(_options
, state
, *this);
3252 lazyBindingSection
= state
.addAtom(*_lazyBindingInfoAtom
);
3254 _exportInfoAtom
= new ExportInfoAtom
<arm64
>(_options
, state
, *this);
3255 exportSection
= state
.addAtom(*_exportInfoAtom
);
3257 if ( _hasLocalRelocations
) {
3258 _localRelocsAtom
= new LocalRelocationsAtom
<arm64
>(_options
, state
, *this);
3259 localRelocationsSection
= state
.addAtom(*_localRelocsAtom
);
3261 if ( _hasSplitSegInfo
) {
3262 _splitSegInfoAtom
= new SplitSegInfoAtom
<arm64
>(_options
, state
, *this);
3263 splitSegInfoSection
= state
.addAtom(*_splitSegInfoAtom
);
3265 if ( _hasFunctionStartsInfo
) {
3266 _functionStartsAtom
= new FunctionStartsAtom
<arm64
>(_options
, state
, *this);
3267 functionStartsSection
= state
.addAtom(*_functionStartsAtom
);
3269 if ( _hasDataInCodeInfo
) {
3270 _dataInCodeAtom
= new DataInCodeAtom
<arm64
>(_options
, state
, *this);
3271 dataInCodeSection
= state
.addAtom(*_dataInCodeAtom
);
3273 if ( _hasOptimizationHints
) {
3274 _optimizationHintsAtom
= new OptimizationHintsAtom
<arm64
>(_options
, state
, *this);
3275 optimizationHintsSection
= state
.addAtom(*_optimizationHintsAtom
);
3277 if ( _hasDependentDRInfo
) {
3278 _dependentDRInfoAtom
= new DependentDRAtom
<arm64
>(_options
, state
, *this);
3279 dependentDRsSection
= state
.addAtom(*_dependentDRInfoAtom
);
3281 if ( _hasSymbolTable
) {
3282 _symbolTableAtom
= new SymbolTableAtom
<arm64
>(_options
, state
, *this);
3283 symbolTableSection
= state
.addAtom(*_symbolTableAtom
);
3285 if ( _hasExternalRelocations
) {
3286 _externalRelocsAtom
= new ExternalRelocationsAtom
<arm64
>(_options
, state
, *this);
3287 externalRelocationsSection
= state
.addAtom(*_externalRelocsAtom
);
3289 if ( _hasSymbolTable
) {
3290 _indirectSymbolTableAtom
= new IndirectSymbolTableAtom
<arm64
>(_options
, state
, *this);
3291 indirectSymbolTableSection
= state
.addAtom(*_indirectSymbolTableAtom
);
3292 _stringPoolAtom
= new StringPoolAtom(_options
, state
, *this, 4);
3293 stringPoolSection
= state
.addAtom(*_stringPoolAtom
);
3298 throw "unknown architecture";
3302 void OutputFile::addLoadCommands(ld::Internal
& state
)
3304 switch ( _options
.architecture() ) {
3305 #if SUPPORT_ARCH_x86_64
3306 case CPU_TYPE_X86_64
:
3307 _headersAndLoadCommandAtom
= new HeaderAndLoadCommandsAtom
<x86_64
>(_options
, state
, *this);
3308 headerAndLoadCommandsSection
= state
.addAtom(*_headersAndLoadCommandAtom
);
3311 #if SUPPORT_ARCH_arm_any
3313 _headersAndLoadCommandAtom
= new HeaderAndLoadCommandsAtom
<arm
>(_options
, state
, *this);
3314 headerAndLoadCommandsSection
= state
.addAtom(*_headersAndLoadCommandAtom
);
3317 #if SUPPORT_ARCH_arm64
3318 case CPU_TYPE_ARM64
:
3319 _headersAndLoadCommandAtom
= new HeaderAndLoadCommandsAtom
<arm64
>(_options
, state
, *this);
3320 headerAndLoadCommandsSection
= state
.addAtom(*_headersAndLoadCommandAtom
);
3323 #if SUPPORT_ARCH_i386
3325 _headersAndLoadCommandAtom
= new HeaderAndLoadCommandsAtom
<x86
>(_options
, state
, *this);
3326 headerAndLoadCommandsSection
= state
.addAtom(*_headersAndLoadCommandAtom
);
3330 throw "unknown architecture";
3334 uint32_t OutputFile::dylibCount()
3336 return _dylibsToLoad
.size();
3339 const ld::dylib::File
* OutputFile::dylibByOrdinal(unsigned int ordinal
)
3341 assert( ordinal
> 0 );
3342 assert( ordinal
<= _dylibsToLoad
.size() );
3343 return _dylibsToLoad
[ordinal
-1];
3346 bool OutputFile::hasOrdinalForInstallPath(const char* path
, int* ordinal
)
3348 for (std::map
<const ld::dylib::File
*, int>::const_iterator it
= _dylibToOrdinal
.begin(); it
!= _dylibToOrdinal
.end(); ++it
) {
3349 const char* installPath
= it
->first
->installPath();
3350 if ( (installPath
!= NULL
) && (strcmp(path
, installPath
) == 0) ) {
3351 *ordinal
= it
->second
;
3358 uint32_t OutputFile::dylibToOrdinal(const ld::dylib::File
* dylib
)
3360 return _dylibToOrdinal
[dylib
];
3364 void OutputFile::buildDylibOrdinalMapping(ld::Internal
& state
)
3366 // count non-public re-exported dylibs
3367 unsigned int nonPublicReExportCount
= 0;
3368 for (std::vector
<ld::dylib::File
*>::iterator it
= state
.dylibs
.begin(); it
!= state
.dylibs
.end(); ++it
) {
3369 ld::dylib::File
* aDylib
= *it
;
3370 if ( aDylib
->willBeReExported() && ! aDylib
->hasPublicInstallName() )
3371 ++nonPublicReExportCount
;
3374 // look at each dylib supplied in state
3375 bool hasReExports
= false;
3376 bool haveLazyDylibs
= false;
3377 for (std::vector
<ld::dylib::File
*>::iterator it
= state
.dylibs
.begin(); it
!= state
.dylibs
.end(); ++it
) {
3378 ld::dylib::File
* aDylib
= *it
;
3380 if ( aDylib
== state
.bundleLoader
) {
3381 _dylibToOrdinal
[aDylib
] = BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE
;
3383 else if ( this->hasOrdinalForInstallPath(aDylib
->installPath(), &ordinal
) ) {
3384 // already have a dylib with that install path, map all uses to that ordinal
3385 _dylibToOrdinal
[aDylib
] = ordinal
;
3387 else if ( aDylib
->willBeLazyLoadedDylib() ) {
3388 // all lazy dylib need to be at end of ordinals
3389 haveLazyDylibs
= true;
3391 else if ( aDylib
->willBeReExported() && ! aDylib
->hasPublicInstallName() && (nonPublicReExportCount
>= 2) ) {
3392 _dylibsToLoad
.push_back(aDylib
);
3393 _dylibToOrdinal
[aDylib
] = BIND_SPECIAL_DYLIB_SELF
;
3396 // first time this install path seen, create new ordinal
3397 _dylibsToLoad
.push_back(aDylib
);
3398 _dylibToOrdinal
[aDylib
] = _dylibsToLoad
.size();
3400 if ( aDylib
->explicitlyLinked() && aDylib
->willBeReExported() )
3401 hasReExports
= true;
3403 if ( haveLazyDylibs
) {
3404 // second pass to determine ordinals for lazy loaded dylibs
3405 for (std::vector
<ld::dylib::File
*>::iterator it
= state
.dylibs
.begin(); it
!= state
.dylibs
.end(); ++it
) {
3406 ld::dylib::File
* aDylib
= *it
;
3407 if ( aDylib
->willBeLazyLoadedDylib() ) {
3409 if ( this->hasOrdinalForInstallPath(aDylib
->installPath(), &ordinal
) ) {
3410 // already have a dylib with that install path, map all uses to that ordinal
3411 _dylibToOrdinal
[aDylib
] = ordinal
;
3414 // first time this install path seen, create new ordinal
3415 _dylibsToLoad
.push_back(aDylib
);
3416 _dylibToOrdinal
[aDylib
] = _dylibsToLoad
.size();
3421 _noReExportedDylibs
= !hasReExports
;
3422 //fprintf(stderr, "dylibs:\n");
3423 //for (std::map<const ld::dylib::File*, int>::const_iterator it = _dylibToOrdinal.begin(); it != _dylibToOrdinal.end(); ++it) {
3424 // fprintf(stderr, " %p ord=%u, install_name=%s\n",it->first, it->second, it->first->installPath());
3428 uint32_t OutputFile::lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress
)
3430 return _lazyPointerAddressToInfoOffset
[lpAddress
];
3433 void OutputFile::setLazyBindingInfoOffset(uint64_t lpAddress
, uint32_t lpInfoOffset
)
3435 _lazyPointerAddressToInfoOffset
[lpAddress
] = lpInfoOffset
;
3438 int OutputFile::compressedOrdinalForAtom(const ld::Atom
* target
)
3440 // flat namespace images use zero for all ordinals
3441 if ( _options
.nameSpace() != Options::kTwoLevelNameSpace
)
3442 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP
;
3444 // handle -interposable
3445 if ( target
->definition() == ld::Atom::definitionRegular
)
3446 return BIND_SPECIAL_DYLIB_SELF
;
3449 const ld::dylib::File
* dylib
= dynamic_cast<const ld::dylib::File
*>(target
->file());
3450 if ( dylib
!= NULL
) {
3451 std::map
<const ld::dylib::File
*, int>::iterator pos
= _dylibToOrdinal
.find(dylib
);
3452 if ( pos
!= _dylibToOrdinal
.end() )
3454 assert(0 && "dylib not assigned ordinal");
3457 // handle undefined dynamic_lookup
3458 if ( _options
.undefinedTreatment() == Options::kUndefinedDynamicLookup
)
3459 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP
;
3462 if ( _options
.allowedUndefined(target
->name()) )
3463 return BIND_SPECIAL_DYLIB_FLAT_LOOKUP
;
3465 throw "can't find ordinal for imported symbol";
3469 bool OutputFile::isPcRelStore(ld::Fixup::Kind kind
)
3472 case ld::Fixup::kindStoreX86BranchPCRel8
:
3473 case ld::Fixup::kindStoreX86BranchPCRel32
:
3474 case ld::Fixup::kindStoreX86PCRel8
:
3475 case ld::Fixup::kindStoreX86PCRel16
:
3476 case ld::Fixup::kindStoreX86PCRel32
:
3477 case ld::Fixup::kindStoreX86PCRel32_1
:
3478 case ld::Fixup::kindStoreX86PCRel32_2
:
3479 case ld::Fixup::kindStoreX86PCRel32_4
:
3480 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
3481 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
3482 case ld::Fixup::kindStoreX86PCRel32GOT
:
3483 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
3484 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
3485 case ld::Fixup::kindStoreARMBranch24
:
3486 case ld::Fixup::kindStoreThumbBranch22
:
3487 case ld::Fixup::kindStoreARMLoad12
:
3488 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
3489 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
3490 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
3491 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
3492 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
3493 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
3494 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
3495 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
3496 #if SUPPORT_ARCH_arm64
3497 case ld::Fixup::kindStoreARM64Page21
:
3498 case ld::Fixup::kindStoreARM64PageOff12
:
3499 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
3500 case ld::Fixup::kindStoreARM64GOTLoadPageOff12
:
3501 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
3502 case ld::Fixup::kindStoreARM64GOTLeaPageOff12
:
3503 case ld::Fixup::kindStoreARM64PCRelToGOT
:
3504 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
3505 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
3506 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
3507 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
3508 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
3509 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
3512 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
3513 #if SUPPORT_ARCH_arm64
3514 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
3516 return (_options
.outputKind() != Options::kKextBundle
);
3523 bool OutputFile::isStore(ld::Fixup::Kind kind
)
3526 case ld::Fixup::kindNone
:
3527 case ld::Fixup::kindNoneFollowOn
:
3528 case ld::Fixup::kindNoneGroupSubordinate
:
3529 case ld::Fixup::kindNoneGroupSubordinateFDE
:
3530 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
3531 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
3532 case ld::Fixup::kindSetTargetAddress
:
3533 case ld::Fixup::kindSubtractTargetAddress
:
3534 case ld::Fixup::kindAddAddend
:
3535 case ld::Fixup::kindSubtractAddend
:
3536 case ld::Fixup::kindSetTargetImageOffset
:
3537 case ld::Fixup::kindSetTargetSectionOffset
:
3546 bool OutputFile::setsTarget(ld::Fixup::Kind kind
)
3549 case ld::Fixup::kindSetTargetAddress
:
3550 case ld::Fixup::kindLazyTarget
:
3551 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
3552 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
3553 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
3554 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
3555 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
3556 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
3557 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
3558 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
3559 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
3560 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
3561 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
3562 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
3563 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
3564 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
3565 #if SUPPORT_ARCH_arm64
3566 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
3567 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
3568 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
3569 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
3570 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
3571 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
3572 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
3575 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
3576 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
3577 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
3578 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
3579 case ld::Fixup::kindStoreARM64DtraceCallSiteNop
:
3580 case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear
:
3581 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
3582 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
3583 return (_options
.outputKind() == Options::kObjectFile
);
3590 bool OutputFile::isPointerToTarget(ld::Fixup::Kind kind
)
3593 case ld::Fixup::kindSetTargetAddress
:
3594 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
3595 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
3596 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
3597 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
3598 case ld::Fixup::kindLazyTarget
:
3605 bool OutputFile::isPointerFromTarget(ld::Fixup::Kind kind
)
3608 case ld::Fixup::kindSubtractTargetAddress
:
3617 uint64_t OutputFile::lookBackAddend(ld::Fixup::iterator fit
)
3619 uint64_t addend
= 0;
3620 switch ( fit
->clusterSize
) {
3621 case ld::Fixup::k1of1
:
3622 case ld::Fixup::k1of2
:
3623 case ld::Fixup::k2of2
:
3625 case ld::Fixup::k2of3
:
3627 switch ( fit
->kind
) {
3628 case ld::Fixup::kindAddAddend
:
3629 addend
+= fit
->u
.addend
;
3631 case ld::Fixup::kindSubtractAddend
:
3632 addend
-= fit
->u
.addend
;
3635 throw "unexpected fixup kind for binding";
3638 case ld::Fixup::k1of3
:
3640 switch ( fit
->kind
) {
3641 case ld::Fixup::kindAddAddend
:
3642 addend
+= fit
->u
.addend
;
3644 case ld::Fixup::kindSubtractAddend
:
3645 addend
-= fit
->u
.addend
;
3648 throw "unexpected fixup kind for binding";
3652 throw "unexpected fixup cluster size for binding";
3658 void OutputFile::generateLinkEditInfo(ld::Internal
& state
)
3660 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
3661 ld::Internal::FinalSection
* sect
= *sit
;
3662 // record end of last __TEXT section encrypted iPhoneOS apps.
3663 if ( _options
.makeEncryptable() && (strcmp(sect
->segmentName(), "__TEXT") == 0) ) {
3664 _encryptedTEXTendOffset
= pageAlign(sect
->fileOffset
+ sect
->size
);
3666 bool objc1ClassRefSection
= ( (sect
->type() == ld::Section::typeCStringPointer
)
3667 && (strcmp(sect
->sectionName(), "__cls_refs") == 0)
3668 && (strcmp(sect
->segmentName(), "__OBJC") == 0) );
3669 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
3670 const ld::Atom
* atom
= *ait
;
3672 // Record regular atoms that override a dylib's weak definitions
3673 if ( (atom
->scope() == ld::Atom::scopeGlobal
) && atom
->overridesDylibsWeakDef() ) {
3674 if ( _options
.makeCompressedDyldInfo() ) {
3675 uint8_t wtype
= BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB
;
3676 bool nonWeakDef
= (atom
->combine() == ld::Atom::combineNever
);
3677 _weakBindingInfo
.push_back(BindingInfo(wtype
, atom
->name(), nonWeakDef
, atom
->finalAddress(), 0));
3679 this->overridesWeakExternalSymbols
= true;
3680 if ( _options
.warnWeakExports() )
3681 warning("overrides weak external symbol: %s", atom
->name());
3684 ld::Fixup
* fixupWithTarget
= NULL
;
3685 ld::Fixup
* fixupWithMinusTarget
= NULL
;
3686 ld::Fixup
* fixupWithStore
= NULL
;
3687 ld::Fixup
* fixupWithAddend
= NULL
;
3688 const ld::Atom
* target
= NULL
;
3689 const ld::Atom
* minusTarget
= NULL
;
3690 uint64_t targetAddend
= 0;
3691 uint64_t minusTargetAddend
= 0;
3692 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(); fit
!= atom
->fixupsEnd(); ++fit
) {
3693 if ( fit
->firstInCluster() ) {
3694 fixupWithTarget
= NULL
;
3695 fixupWithMinusTarget
= NULL
;
3696 fixupWithStore
= NULL
;
3700 minusTargetAddend
= 0;
3702 if ( this->setsTarget(fit
->kind
) ) {
3703 switch ( fit
->binding
) {
3704 case ld::Fixup::bindingNone
:
3705 case ld::Fixup::bindingByNameUnbound
:
3707 case ld::Fixup::bindingByContentBound
:
3708 case ld::Fixup::bindingDirectlyBound
:
3709 fixupWithTarget
= fit
;
3710 target
= fit
->u
.target
;
3712 case ld::Fixup::bindingsIndirectlyBound
:
3713 fixupWithTarget
= fit
;
3714 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
3717 assert(target
!= NULL
);
3719 switch ( fit
->kind
) {
3720 case ld::Fixup::kindAddAddend
:
3721 targetAddend
= fit
->u
.addend
;
3722 fixupWithAddend
= fit
;
3724 case ld::Fixup::kindSubtractAddend
:
3725 minusTargetAddend
= fit
->u
.addend
;
3726 fixupWithAddend
= fit
;
3728 case ld::Fixup::kindSubtractTargetAddress
:
3729 switch ( fit
->binding
) {
3730 case ld::Fixup::bindingNone
:
3731 case ld::Fixup::bindingByNameUnbound
:
3733 case ld::Fixup::bindingByContentBound
:
3734 case ld::Fixup::bindingDirectlyBound
:
3735 fixupWithMinusTarget
= fit
;
3736 minusTarget
= fit
->u
.target
;
3738 case ld::Fixup::bindingsIndirectlyBound
:
3739 fixupWithMinusTarget
= fit
;
3740 minusTarget
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
3743 assert(minusTarget
!= NULL
);
3745 case ld::Fixup::kindDataInCodeStartData
:
3746 case ld::Fixup::kindDataInCodeStartJT8
:
3747 case ld::Fixup::kindDataInCodeStartJT16
:
3748 case ld::Fixup::kindDataInCodeStartJT32
:
3749 case ld::Fixup::kindDataInCodeStartJTA32
:
3750 case ld::Fixup::kindDataInCodeEnd
:
3751 hasDataInCode
= true;
3756 if ( this->isStore(fit
->kind
) ) {
3757 fixupWithStore
= fit
;
3759 if ( fit
->lastInCluster() ) {
3760 if ( (fixupWithStore
!= NULL
) && (target
!= NULL
) ) {
3761 if ( _options
.outputKind() == Options::kObjectFile
) {
3762 this->addSectionRelocs(state
, sect
, atom
, fixupWithTarget
, fixupWithMinusTarget
, fixupWithAddend
, fixupWithStore
,
3763 target
, minusTarget
, targetAddend
, minusTargetAddend
);
3766 if ( _options
.makeCompressedDyldInfo() ) {
3767 this->addDyldInfo(state
, sect
, atom
, fixupWithTarget
, fixupWithMinusTarget
, fixupWithStore
,
3768 target
, minusTarget
, targetAddend
, minusTargetAddend
);
3771 this->addClassicRelocs(state
, sect
, atom
, fixupWithTarget
, fixupWithMinusTarget
, fixupWithStore
,
3772 target
, minusTarget
, targetAddend
, minusTargetAddend
);
3776 else if ( objc1ClassRefSection
&& (target
!= NULL
) && (fixupWithStore
== NULL
) ) {
3777 // check for class refs to lazy loaded dylibs
3778 const ld::dylib::File
* dylib
= dynamic_cast<const ld::dylib::File
*>(target
->file());
3779 if ( (dylib
!= NULL
) && dylib
->willBeLazyLoadedDylib() )
3780 throwf("illegal class reference to %s in lazy loaded dylib %s", target
->name(), dylib
->path());
3789 void OutputFile::noteTextReloc(const ld::Atom
* atom
, const ld::Atom
* target
)
3791 if ( (atom
->contentType() == ld::Atom::typeStub
) || (atom
->contentType() == ld::Atom::typeStubHelper
) ) {
3792 // silently let stubs (synthesized by linker) use text relocs
3794 else if ( _options
.allowTextRelocs() ) {
3795 if ( _options
.warnAboutTextRelocs() )
3796 warning("text reloc in %s to %s", atom
->name(), target
->name());
3798 else if ( _options
.positionIndependentExecutable() && (_options
.outputKind() == Options::kDynamicExecutable
)
3799 && ((_options
.iOSVersionMin() >= ld::iOS_4_3
) || (_options
.macosxVersionMin() >= ld::mac10_7
)) ) {
3800 if ( ! this->pieDisabled
) {
3801 #if SUPPORT_ARCH_arm64
3802 if ( _options
.architecture() == CPU_TYPE_ARM64
) {
3803 const char* demangledName
= strdup(_options
.demangleSymbol(atom
->name()));
3804 throwf("Absolute addressing not allowed in arm64 code but used in '%s' referencing '%s'", demangledName
, _options
.demangleSymbol(target
->name()));
3809 warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
3810 "but used in %s from %s. "
3811 "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie",
3812 atom
->name(), atom
->file()->path());
3815 this->pieDisabled
= true;
3817 else if ( (target
->scope() == ld::Atom::scopeGlobal
) && (target
->combine() == ld::Atom::combineByName
) ) {
3818 throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target
->name(), target
->file()->path(), atom
->name(), atom
->file()->path());
3821 if ( (target
->file() != NULL
) && (atom
->file() != NULL
) )
3822 throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target
->name(), target
->file()->path(), atom
->name(), atom
->file()->path());
3824 throwf("illegal text reloc in '%s' to '%s'", atom
->name(), target
->name());
3828 void OutputFile::addDyldInfo(ld::Internal
& state
, ld::Internal::FinalSection
* sect
, const ld::Atom
* atom
,
3829 ld::Fixup
* fixupWithTarget
, ld::Fixup
* fixupWithMinusTarget
, ld::Fixup
* fixupWithStore
,
3830 const ld::Atom
* target
, const ld::Atom
* minusTarget
,
3831 uint64_t targetAddend
, uint64_t minusTargetAddend
)
3833 if ( sect
->isSectionHidden() )
3836 // no need to rebase or bind PCRel stores
3837 if ( this->isPcRelStore(fixupWithStore
->kind
) ) {
3838 // as long as target is in same linkage unit
3839 if ( (target
== NULL
) || (target
->definition() != ld::Atom::definitionProxy
) ) {
3840 // make sure target is not global and weak
3841 if ( (target
->scope() == ld::Atom::scopeGlobal
) && (target
->combine() == ld::Atom::combineByName
) && (target
->definition() == ld::Atom::definitionRegular
)) {
3842 if ( (atom
->section().type() == ld::Section::typeCFI
)
3843 || (atom
->section().type() == ld::Section::typeDtraceDOF
)
3844 || (atom
->section().type() == ld::Section::typeUnwindInfo
) ) {
3845 // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
3848 // <rdar://problem/13700961> spurious warning when weak function has reference to itself
3849 if ( fixupWithTarget
->binding
== ld::Fixup::bindingDirectlyBound
) {
3850 // ok to ignore pc-rel references within a weak function to itself
3853 // Have direct reference to weak-global. This should be an indrect reference
3854 const char* demangledName
= strdup(_options
.demangleSymbol(atom
->name()));
3855 warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
3856 "This was likely caused by different translation units being compiled with different visibility settings.",
3857 demangledName
, _options
.demangleSymbol(target
->name()));
3863 // no need to rebase or bind PIC internal pointer diff
3864 if ( minusTarget
!= NULL
) {
3865 // with pointer diffs, both need to be in same linkage unit
3866 assert(minusTarget
->definition() != ld::Atom::definitionProxy
);
3867 assert(target
!= NULL
);
3868 assert(target
->definition() != ld::Atom::definitionProxy
);
3869 if ( target
== minusTarget
) {
3870 // This is a compile time constant and could have been optimized away by compiler
3874 // check if target of pointer-diff is global and weak
3875 if ( (target
->scope() == ld::Atom::scopeGlobal
) && (target
->combine() == ld::Atom::combineByName
) && (target
->definition() == ld::Atom::definitionRegular
) ) {
3876 if ( (atom
->section().type() == ld::Section::typeCFI
)
3877 || (atom
->section().type() == ld::Section::typeDtraceDOF
)
3878 || (atom
->section().type() == ld::Section::typeUnwindInfo
) ) {
3879 // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
3882 // Have direct reference to weak-global. This should be an indrect reference
3883 const char* demangledName
= strdup(_options
.demangleSymbol(atom
->name()));
3884 warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
3885 "This was likely caused by different translation units being compiled with different visibility settings.",
3886 demangledName
, _options
.demangleSymbol(target
->name()));
3891 // no need to rebase or bind an atom's references to itself if the output is not slidable
3892 if ( (atom
== target
) && !_options
.outputSlidable() )
3895 // cluster has no target, so needs no rebasing or binding
3896 if ( target
== NULL
)
3899 bool inReadOnlySeg
= ((_options
.initialSegProtection(sect
->segmentName()) & VM_PROT_WRITE
) == 0);
3900 bool needsRebase
= false;
3901 bool needsBinding
= false;
3902 bool needsLazyBinding
= false;
3903 bool needsWeakBinding
= false;
3905 uint8_t rebaseType
= REBASE_TYPE_POINTER
;
3906 uint8_t type
= BIND_TYPE_POINTER
;
3907 const ld::dylib::File
* dylib
= dynamic_cast<const ld::dylib::File
*>(target
->file());
3908 bool weak_import
= (fixupWithTarget
->weakImport
|| ((dylib
!= NULL
) && dylib
->forcedWeakLinked()));
3909 uint64_t address
= atom
->finalAddress() + fixupWithTarget
->offsetInAtom
;
3910 uint64_t addend
= targetAddend
- minusTargetAddend
;
3912 // special case lazy pointers
3913 if ( fixupWithTarget
->kind
== ld::Fixup::kindLazyTarget
) {
3914 assert(fixupWithTarget
->u
.target
== target
);
3915 assert(addend
== 0);
3916 // lazy dylib lazy pointers do not have any dyld info
3917 if ( atom
->section().type() == ld::Section::typeLazyDylibPointer
)
3919 // lazy binding to weak definitions are done differently
3920 // they are directly bound to target, then have a weak bind in case of a collision
3921 if ( target
->combine() == ld::Atom::combineByName
) {
3922 if ( target
->definition() == ld::Atom::definitionProxy
) {
3923 // weak def exported from another dylib
3924 // must non-lazy bind to it plus have weak binding info in case of collision
3925 needsBinding
= true;
3926 needsWeakBinding
= true;
3929 // weak def in this linkage unit.
3930 // just rebase, plus have weak binding info in case of collision
3931 // this will be done by other cluster on lazy pointer atom
3934 else if ( target
->contentType() == ld::Atom::typeResolver
) {
3935 // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
3936 // <rdar://problem/12629331> Resolver function run before initializers when overriding the dyld shared cache
3937 // The lazy pointers used by stubs used when non-lazy binding to a resolver are not normal lazy pointers
3938 // and should not be in lazy binding info.
3939 needsLazyBinding
= false;
3942 // normal case of a pointer to non-weak-def symbol, so can lazily bind
3943 needsLazyBinding
= true;
3947 // everything except lazy pointers
3948 switch ( target
->definition() ) {
3949 case ld::Atom::definitionProxy
:
3950 if ( (dylib
!= NULL
) && dylib
->willBeLazyLoadedDylib() )
3951 throwf("illegal data reference to %s in lazy loaded dylib %s", target
->name(), dylib
->path());
3952 if ( target
->contentType() == ld::Atom::typeTLV
) {
3953 if ( sect
->type() != ld::Section::typeTLVPointers
)
3954 throwf("illegal data reference in %s to thread local variable %s in dylib %s",
3955 atom
->name(), target
->name(), dylib
->path());
3957 if ( inReadOnlySeg
)
3958 type
= BIND_TYPE_TEXT_ABSOLUTE32
;
3959 needsBinding
= true;
3960 if ( target
->combine() == ld::Atom::combineByName
)
3961 needsWeakBinding
= true;
3963 case ld::Atom::definitionRegular
:
3964 case ld::Atom::definitionTentative
:
3965 // only slideable images need rebasing info
3966 if ( _options
.outputSlidable() ) {
3969 // references to internal symbol never need binding
3970 if ( target
->scope() != ld::Atom::scopeGlobal
)
3972 // reference to global weak def needs weak binding
3973 if ( (target
->combine() == ld::Atom::combineByName
) && (target
->definition() == ld::Atom::definitionRegular
) )
3974 needsWeakBinding
= true;
3975 else if ( _options
.outputKind() == Options::kDynamicExecutable
) {
3976 // in main executables, the only way regular symbols are indirected is if -interposable is used
3977 if ( _options
.interposable(target
->name()) ) {
3978 needsRebase
= false;
3979 needsBinding
= true;
3983 // for flat-namespace or interposable two-level-namespace
3984 // all references to exported symbols get indirected
3985 if ( (_options
.nameSpace() != Options::kTwoLevelNameSpace
) || _options
.interposable(target
->name()) ) {
3986 // <rdar://problem/5254468> no external relocs for flat objc classes
3987 if ( strncmp(target
->name(), ".objc_class_", 12) == 0 )
3989 // no rebase info for references to global symbols that will have binding info
3990 needsRebase
= false;
3991 needsBinding
= true;
3993 else if ( _options
.forceCoalesce(target
->name()) ) {
3994 needsWeakBinding
= true;
3998 case ld::Atom::definitionAbsolute
:
4003 // <rdar://problem/13828711> if target is an import alias, use base of alias
4004 if ( target
->isAlias() && (target
->definition() == ld::Atom::definitionProxy
) ) {
4005 for (ld::Fixup::iterator fit
= target
->fixupsBegin(), end
=target
->fixupsEnd(); fit
!= end
; ++fit
) {
4006 if ( fit
->firstInCluster() ) {
4007 if ( fit
->kind
== ld::Fixup::kindNoneFollowOn
) {
4008 if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
4009 //fprintf(stderr, "switching import of %s to import of %s\n", target->name(), fit->u.target->name());
4010 target
= fit
->u
.target
;
4017 // record dyld info for this cluster
4018 if ( needsRebase
) {
4019 if ( inReadOnlySeg
) {
4020 noteTextReloc(atom
, target
);
4021 sect
->hasLocalRelocs
= true; // so dyld knows to change permissions on __TEXT segment
4022 rebaseType
= REBASE_TYPE_TEXT_ABSOLUTE32
;
4024 if ( _options
.sharedRegionEligible() ) {
4025 // <rdar://problem/13287063> when range checking, ignore high byte of arm64 addends
4026 uint64_t checkAddend
= addend
;
4027 if ( _options
.architecture() == CPU_TYPE_ARM64
)
4028 checkAddend
&= 0x0FFFFFFFFFFFFFFFULL
;
4029 if ( checkAddend
!= 0 ) {
4030 // make sure the addend does not cause the pointer to point outside the target's segment
4031 // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
4032 uint64_t targetAddress
= target
->finalAddress();
4033 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4034 ld::Internal::FinalSection
* sct
= *sit
;
4035 uint64_t sctEnd
= (sct
->address
+sct
->size
);
4036 if ( (sct
->address
<= targetAddress
) && (targetAddress
< sctEnd
) ) {
4037 if ( (targetAddress
+checkAddend
) > sctEnd
) {
4038 warning("data symbol %s from %s has pointer to %s + 0x%08llX. "
4039 "That large of an addend may disable %s from being put in the dyld shared cache.",
4040 atom
->name(), atom
->file()->path(), target
->name(), addend
, _options
.installPath() );
4046 _rebaseInfo
.push_back(RebaseInfo(rebaseType
, address
));
4048 if ( needsBinding
) {
4049 if ( inReadOnlySeg
) {
4050 noteTextReloc(atom
, target
);
4051 sect
->hasExternalRelocs
= true; // so dyld knows to change permissions on __TEXT segment
4053 _bindingInfo
.push_back(BindingInfo(type
, this->compressedOrdinalForAtom(target
), target
->name(), weak_import
, address
, addend
));
4055 if ( needsLazyBinding
) {
4056 if ( _options
.bindAtLoad() )
4057 _bindingInfo
.push_back(BindingInfo(type
, this->compressedOrdinalForAtom(target
), target
->name(), weak_import
, address
, addend
));
4059 _lazyBindingInfo
.push_back(BindingInfo(type
, this->compressedOrdinalForAtom(target
), target
->name(), weak_import
, address
, addend
));
4061 if ( needsWeakBinding
)
4062 _weakBindingInfo
.push_back(BindingInfo(type
, 0, target
->name(), false, address
, addend
));
4066 void OutputFile::addClassicRelocs(ld::Internal
& state
, ld::Internal::FinalSection
* sect
, const ld::Atom
* atom
,
4067 ld::Fixup
* fixupWithTarget
, ld::Fixup
* fixupWithMinusTarget
, ld::Fixup
* fixupWithStore
,
4068 const ld::Atom
* target
, const ld::Atom
* minusTarget
,
4069 uint64_t targetAddend
, uint64_t minusTargetAddend
)
4071 if ( sect
->isSectionHidden() )
4074 // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
4075 if ( sect
->type() == ld::Section::typeNonLazyPointer
) {
4076 // except kexts and static pie which *do* use relocations
4077 switch (_options
.outputKind()) {
4078 case Options::kKextBundle
:
4080 case Options::kStaticExecutable
:
4081 if ( _options
.positionIndependentExecutable() )
4083 // else fall into default case
4085 assert(target
!= NULL
);
4086 assert(fixupWithTarget
!= NULL
);
4091 // no need to rebase or bind PCRel stores
4092 if ( this->isPcRelStore(fixupWithStore
->kind
) ) {
4093 // as long as target is in same linkage unit
4094 if ( (target
== NULL
) || (target
->definition() != ld::Atom::definitionProxy
) )
4098 // no need to rebase or bind PIC internal pointer diff
4099 if ( minusTarget
!= NULL
) {
4100 // with pointer diffs, both need to be in same linkage unit
4101 assert(minusTarget
->definition() != ld::Atom::definitionProxy
);
4102 assert(target
!= NULL
);
4103 assert(target
->definition() != ld::Atom::definitionProxy
);
4104 // make sure target is not global and weak
4105 if ( (target
->scope() == ld::Atom::scopeGlobal
) && (target
->combine() == ld::Atom::combineByName
)
4106 && (atom
->section().type() != ld::Section::typeCFI
)
4107 && (atom
->section().type() != ld::Section::typeDtraceDOF
)
4108 && (atom
->section().type() != ld::Section::typeUnwindInfo
)
4109 && (minusTarget
!= target
) ) {
4110 // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
4111 throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom
->name(), target
->name());
4116 // cluster has no target, so needs no rebasing or binding
4117 if ( target
== NULL
)
4120 assert(_localRelocsAtom
!= NULL
);
4121 uint64_t relocAddress
= atom
->finalAddress() + fixupWithTarget
->offsetInAtom
- _localRelocsAtom
->relocBaseAddress(state
);
4123 bool inReadOnlySeg
= ( strcmp(sect
->segmentName(), "__TEXT") == 0 );
4124 bool needsLocalReloc
= false;
4125 bool needsExternReloc
= false;
4127 switch ( fixupWithStore
->kind
) {
4128 case ld::Fixup::kindLazyTarget
:
4129 // lazy pointers don't need relocs
4131 case ld::Fixup::kindStoreLittleEndian32
:
4132 case ld::Fixup::kindStoreLittleEndian64
:
4133 case ld::Fixup::kindStoreBigEndian32
:
4134 case ld::Fixup::kindStoreBigEndian64
:
4135 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
4136 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
4137 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
4138 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
4140 switch ( target
->definition() ) {
4141 case ld::Atom::definitionProxy
:
4142 needsExternReloc
= true;
4144 case ld::Atom::definitionRegular
:
4145 case ld::Atom::definitionTentative
:
4146 // only slideable images need local relocs
4147 if ( _options
.outputSlidable() )
4148 needsLocalReloc
= true;
4149 // references to internal symbol never need binding
4150 if ( target
->scope() != ld::Atom::scopeGlobal
)
4152 // reference to global weak def needs weak binding in dynamic images
4153 if ( (target
->combine() == ld::Atom::combineByName
)
4154 && (target
->definition() == ld::Atom::definitionRegular
)
4155 && (_options
.outputKind() != Options::kStaticExecutable
)
4156 && (_options
.outputKind() != Options::kPreload
)
4157 && (atom
!= target
) ) {
4158 needsExternReloc
= true;
4160 else if ( _options
.outputKind() == Options::kDynamicExecutable
) {
4161 // in main executables, the only way regular symbols are indirected is if -interposable is used
4162 if ( _options
.interposable(target
->name()) )
4163 needsExternReloc
= true;
4166 // for flat-namespace or interposable two-level-namespace
4167 // all references to exported symbols get indirected
4168 if ( (_options
.nameSpace() != Options::kTwoLevelNameSpace
) || _options
.interposable(target
->name()) ) {
4169 // <rdar://problem/5254468> no external relocs for flat objc classes
4170 if ( strncmp(target
->name(), ".objc_class_", 12) == 0 )
4172 // no rebase info for references to global symbols that will have binding info
4173 needsExternReloc
= true;
4176 if ( needsExternReloc
)
4177 needsLocalReloc
= false;
4179 case ld::Atom::definitionAbsolute
:
4182 if ( needsExternReloc
) {
4183 if ( inReadOnlySeg
)
4184 noteTextReloc(atom
, target
);
4185 const ld::dylib::File
* dylib
= dynamic_cast<const ld::dylib::File
*>(target
->file());
4186 if ( (dylib
!= NULL
) && dylib
->willBeLazyLoadedDylib() )
4187 throwf("illegal data reference to %s in lazy loaded dylib %s", target
->name(), dylib
->path());
4188 _externalRelocsAtom
->addExternalPointerReloc(relocAddress
, target
);
4189 sect
->hasExternalRelocs
= true;
4190 fixupWithTarget
->contentAddendOnly
= true;
4192 else if ( needsLocalReloc
) {
4193 assert(target
!= NULL
);
4194 if ( inReadOnlySeg
)
4195 noteTextReloc(atom
, target
);
4196 _localRelocsAtom
->addPointerReloc(relocAddress
, target
->machoSection());
4197 sect
->hasLocalRelocs
= true;
4200 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
4201 #if SUPPORT_ARCH_arm64
4202 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
4204 if ( _options
.outputKind() == Options::kKextBundle
) {
4205 assert(target
!= NULL
);
4206 if ( target
->definition() == ld::Atom::definitionProxy
) {
4207 _externalRelocsAtom
->addExternalCallSiteReloc(relocAddress
, target
);
4208 fixupWithStore
->contentAddendOnly
= true;
4213 case ld::Fixup::kindStoreARMLow16
:
4214 case ld::Fixup::kindStoreThumbLow16
:
4215 // no way to encode rebasing of binding for these instructions
4216 if ( _options
.outputSlidable() || (target
->definition() == ld::Atom::definitionProxy
) )
4217 throwf("no supported runtime lo16 relocation in %s from %s to %s", atom
->name(), atom
->file()->path(), target
->name());
4220 case ld::Fixup::kindStoreARMHigh16
:
4221 case ld::Fixup::kindStoreThumbHigh16
:
4222 // no way to encode rebasing of binding for these instructions
4223 if ( _options
.outputSlidable() || (target
->definition() == ld::Atom::definitionProxy
) )
4224 throwf("no supported runtime hi16 relocation in %s from %s to %s", atom
->name(), atom
->file()->path(), target
->name());
4233 bool OutputFile::useExternalSectionReloc(const ld::Atom
* atom
, const ld::Atom
* target
, ld::Fixup
* fixupWithTarget
)
4235 if ( (_options
.architecture() == CPU_TYPE_X86_64
) || (_options
.architecture() == CPU_TYPE_ARM64
) ) {
4236 // x86_64 and ARM64 use external relocations for everthing that has a symbol
4237 return ( target
->symbolTableInclusion() != ld::Atom::symbolTableNotIn
);
4240 // <rdar://problem/9513487> support arm branch interworking in -r mode
4241 if ( (_options
.architecture() == CPU_TYPE_ARM
) && (_options
.outputKind() == Options::kObjectFile
) ) {
4242 if ( atom
->isThumb() != target
->isThumb() ) {
4243 switch ( fixupWithTarget
->kind
) {
4244 // have branch that switches mode, then might be 'b' not 'bl'
4245 // Force external relocation, since no way to do local reloc for 'b'
4246 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
4247 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
4255 if ( (_options
.architecture() == CPU_TYPE_I386
) && (_options
.outputKind() == Options::kObjectFile
) ) {
4256 if ( target
->contentType() == ld::Atom::typeTLV
)
4260 // most architectures use external relocations only for references
4261 // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
4262 assert(target
!= NULL
);
4263 if ( target
->definition() == ld::Atom::definitionProxy
)
4265 if ( (target
->definition() == ld::Atom::definitionTentative
) && ! _options
.makeTentativeDefinitionsReal() )
4267 if ( target
->scope() != ld::Atom::scopeGlobal
)
4269 if ( (target
->combine() == ld::Atom::combineByName
) && (target
->definition() == ld::Atom::definitionRegular
) )
4274 bool OutputFile::useSectionRelocAddend(ld::Fixup
* fixupWithTarget
)
4276 #if SUPPORT_ARCH_arm64
4277 if ( _options
.architecture() == CPU_TYPE_ARM64
) {
4278 switch ( fixupWithTarget
->kind
) {
4279 case ld::Fixup::kindStoreARM64Branch26
:
4280 case ld::Fixup::kindStoreARM64Page21
:
4281 case ld::Fixup::kindStoreARM64PageOff12
:
4294 void OutputFile::addSectionRelocs(ld::Internal
& state
, ld::Internal::FinalSection
* sect
, const ld::Atom
* atom
,
4295 ld::Fixup
* fixupWithTarget
, ld::Fixup
* fixupWithMinusTarget
,
4296 ld::Fixup
* fixupWithAddend
, ld::Fixup
* fixupWithStore
,
4297 const ld::Atom
* target
, const ld::Atom
* minusTarget
,
4298 uint64_t targetAddend
, uint64_t minusTargetAddend
)
4300 if ( sect
->isSectionHidden() )
4303 // in -r mode where there will be no labels on __eh_frame section, there is no need for relocations
4304 if ( (sect
->type() == ld::Section::typeCFI
) && _options
.removeEHLabels() )
4307 // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
4308 if ( sect
->type() == ld::Section::typeNonLazyPointer
)
4311 // tentative defs don't have any relocations
4312 if ( sect
->type() == ld::Section::typeTentativeDefs
)
4315 assert(target
!= NULL
);
4316 assert(fixupWithTarget
!= NULL
);
4317 bool targetUsesExternalReloc
= this->useExternalSectionReloc(atom
, target
, fixupWithTarget
);
4318 bool minusTargetUsesExternalReloc
= (minusTarget
!= NULL
) && this->useExternalSectionReloc(atom
, minusTarget
, fixupWithMinusTarget
);
4320 // in x86_64 and arm64 .o files an external reloc means the content contains just the addend
4321 if ( (_options
.architecture() == CPU_TYPE_X86_64
) ||(_options
.architecture() == CPU_TYPE_ARM64
) ) {
4322 if ( targetUsesExternalReloc
) {
4323 fixupWithTarget
->contentAddendOnly
= true;
4324 fixupWithStore
->contentAddendOnly
= true;
4325 if ( this->useSectionRelocAddend(fixupWithStore
) && (fixupWithAddend
!= NULL
) )
4326 fixupWithAddend
->contentIgnoresAddend
= true;
4328 if ( minusTargetUsesExternalReloc
)
4329 fixupWithMinusTarget
->contentAddendOnly
= true;
4332 // for other archs, content is addend only with (non pc-rel) pointers
4333 // pc-rel instructions are funny. If the target is _foo+8 and _foo is
4334 // external, then the pc-rel instruction *evalutates* to the address 8.
4335 if ( targetUsesExternalReloc
) {
4336 // TLV support for i386 acts like RIP relative addressing
4337 // The addend is the offset from the PICBase to the end of the instruction
4338 if ( (_options
.architecture() == CPU_TYPE_I386
)
4339 && (_options
.outputKind() == Options::kObjectFile
)
4340 && (fixupWithStore
->kind
== ld::Fixup::kindStoreX86PCRel32TLVLoad
) ) {
4341 fixupWithTarget
->contentAddendOnly
= true;
4342 fixupWithStore
->contentAddendOnly
= true;
4344 else if ( isPcRelStore(fixupWithStore
->kind
) ) {
4345 fixupWithTarget
->contentDetlaToAddendOnly
= true;
4346 fixupWithStore
->contentDetlaToAddendOnly
= true;
4348 else if ( minusTarget
== NULL
){
4349 fixupWithTarget
->contentAddendOnly
= true;
4350 fixupWithStore
->contentAddendOnly
= true;
4355 if ( fixupWithStore
!= NULL
) {
4356 _sectionsRelocationsAtom
->addSectionReloc(sect
, fixupWithStore
->kind
, atom
, fixupWithStore
->offsetInAtom
,
4357 targetUsesExternalReloc
, minusTargetUsesExternalReloc
,
4358 target
, targetAddend
, minusTarget
, minusTargetAddend
);
4364 void OutputFile::makeSplitSegInfo(ld::Internal
& state
)
4366 if ( !_options
.sharedRegionEligible() )
4369 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4370 ld::Internal::FinalSection
* sect
= *sit
;
4371 if ( sect
->isSectionHidden() )
4373 if ( strcmp(sect
->segmentName(), "__TEXT") != 0 )
4375 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
4376 const ld::Atom
* atom
= *ait
;
4377 const ld::Atom
* target
= NULL
;
4378 const ld::Atom
* fromTarget
= NULL
;
4379 uint64_t accumulator
= 0;
4381 bool hadSubtract
= false;
4382 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
4383 if ( fit
->firstInCluster() )
4385 if ( this->setsTarget(fit
->kind
) ) {
4386 accumulator
= addressOf(state
, fit
, &target
);
4387 thumbTarget
= targetIsThumb(state
, fit
);
4391 switch ( fit
->kind
) {
4392 case ld::Fixup::kindSubtractTargetAddress
:
4393 accumulator
-= addressOf(state
, fit
, &fromTarget
);
4396 case ld::Fixup::kindAddAddend
:
4397 accumulator
+= fit
->u
.addend
;
4399 case ld::Fixup::kindSubtractAddend
:
4400 accumulator
-= fit
->u
.addend
;
4402 case ld::Fixup::kindStoreBigEndian32
:
4403 case ld::Fixup::kindStoreLittleEndian32
:
4404 case ld::Fixup::kindStoreLittleEndian64
:
4405 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
4406 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
4407 // if no subtract, then this is an absolute pointer which means
4408 // there is also a text reloc which update_dyld_shared_cache will use.
4409 if ( ! hadSubtract
)
4412 case ld::Fixup::kindStoreX86PCRel32
:
4413 case ld::Fixup::kindStoreX86PCRel32_1
:
4414 case ld::Fixup::kindStoreX86PCRel32_2
:
4415 case ld::Fixup::kindStoreX86PCRel32_4
:
4416 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
4417 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
4418 case ld::Fixup::kindStoreX86PCRel32GOT
:
4419 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
4420 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
4421 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
4422 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
4423 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
4424 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
4425 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
4426 case ld::Fixup::kindStoreARMLow16
:
4427 case ld::Fixup::kindStoreThumbLow16
:
4428 #if SUPPORT_ARCH_arm64
4429 case ld::Fixup::kindStoreARM64Page21
:
4430 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
4431 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
4432 case ld::Fixup::kindStoreARM64TLVPLoadPage21
:
4433 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
4434 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
4435 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
4436 case ld::Fixup::kindStoreARM64PCRelToGOT
:
4438 assert(target
!= NULL
);
4439 if ( strcmp(sect
->segmentName(), target
->section().segmentName()) != 0 ) {
4440 _splitSegInfos
.push_back(SplitSegInfoEntry(atom
->finalAddress()+fit
->offsetInAtom
,fit
->kind
));
4443 case ld::Fixup::kindStoreARMHigh16
:
4444 case ld::Fixup::kindStoreThumbHigh16
:
4445 assert(target
!= NULL
);
4446 if ( strcmp(sect
->segmentName(), target
->section().segmentName()) != 0 ) {
4447 // hi16 needs to know upper 4-bits of low16 to compute carry
4448 uint32_t extra
= (accumulator
>> 12) & 0xF;
4449 _splitSegInfos
.push_back(SplitSegInfoEntry(atom
->finalAddress()+fit
->offsetInAtom
,fit
->kind
, extra
));
4452 case ld::Fixup::kindSetTargetImageOffset
:
4453 accumulator
= addressOf(state
, fit
, &target
);
4454 assert(target
!= NULL
);
4466 void OutputFile::writeMapFile(ld::Internal
& state
)
4468 if ( _options
.generatedMapPath() != NULL
) {
4469 FILE* mapFile
= fopen(_options
.generatedMapPath(), "w");
4470 if ( mapFile
!= NULL
) {
4471 // write output path
4472 fprintf(mapFile
, "# Path: %s\n", _options
.outputFilePath());
4473 // write output architecure
4474 fprintf(mapFile
, "# Arch: %s\n", _options
.architectureName());
4476 //if ( fUUIDAtom != NULL ) {
4477 // const uint8_t* uuid = fUUIDAtom->getUUID();
4478 // fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
4479 // uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
4480 // uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
4482 // write table of object files
4483 std::map
<const ld::File
*, ld::File::Ordinal
> readerToOrdinal
;
4484 std::map
<ld::File::Ordinal
, const ld::File
*> ordinalToReader
;
4485 std::map
<const ld::File
*, uint32_t> readerToFileOrdinal
;
4486 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4487 ld::Internal::FinalSection
* sect
= *sit
;
4488 if ( sect
->isSectionHidden() )
4490 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
4491 const ld::Atom
* atom
= *ait
;
4492 const ld::File
* reader
= atom
->file();
4493 if ( reader
== NULL
)
4495 ld::File::Ordinal readerOrdinal
= reader
->ordinal();
4496 std::map
<const ld::File
*, ld::File::Ordinal
>::iterator pos
= readerToOrdinal
.find(reader
);
4497 if ( pos
== readerToOrdinal
.end() ) {
4498 readerToOrdinal
[reader
] = readerOrdinal
;
4499 ordinalToReader
[readerOrdinal
] = reader
;
4503 fprintf(mapFile
, "# Object files:\n");
4504 fprintf(mapFile
, "[%3u] %s\n", 0, "linker synthesized");
4505 uint32_t fileIndex
= 1;
4506 for(std::map
<ld::File::Ordinal
, const ld::File
*>::iterator it
= ordinalToReader
.begin(); it
!= ordinalToReader
.end(); ++it
) {
4507 fprintf(mapFile
, "[%3u] %s\n", fileIndex
, it
->second
->path());
4508 readerToFileOrdinal
[it
->second
] = fileIndex
++;
4510 // write table of sections
4511 fprintf(mapFile
, "# Sections:\n");
4512 fprintf(mapFile
, "# Address\tSize \tSegment\tSection\n");
4513 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4514 ld::Internal::FinalSection
* sect
= *sit
;
4515 if ( sect
->isSectionHidden() )
4517 fprintf(mapFile
, "0x%08llX\t0x%08llX\t%s\t%s\n", sect
->address
, sect
->size
,
4518 sect
->segmentName(), sect
->sectionName());
4520 // write table of symbols
4521 fprintf(mapFile
, "# Symbols:\n");
4522 fprintf(mapFile
, "# Address\tSize \tFile Name\n");
4523 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4524 ld::Internal::FinalSection
* sect
= *sit
;
4525 if ( sect
->isSectionHidden() )
4527 //bool isCstring = (sect->type() == ld::Section::typeCString);
4528 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
4530 const ld::Atom
* atom
= *ait
;
4531 const char* name
= atom
->name();
4532 // don't add auto-stripped aliases to .map file
4533 if ( (atom
->size() == 0) && (atom
->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages
) )
4535 if ( atom
->contentType() == ld::Atom::typeCString
) {
4536 strcpy(buffer
, "literal string: ");
4537 strlcat(buffer
, (char*)atom
->rawContentPointer(), 4096);
4540 else if ( (atom
->contentType() == ld::Atom::typeCFI
) && (strcmp(name
, "FDE") == 0) ) {
4541 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(); fit
!= atom
->fixupsEnd(); ++fit
) {
4542 if ( (fit
->kind
== ld::Fixup::kindSetTargetAddress
) && (fit
->clusterSize
== ld::Fixup::k1of4
) ) {
4543 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
4544 if ( fit
->u
.target
->section().type() == ld::Section::typeCode
) {
4545 strcpy(buffer
, "FDE for: ");
4546 strlcat(buffer
, fit
->u
.target
->name(), 4096);
4552 else if ( atom
->contentType() == ld::Atom::typeNonLazyPointer
) {
4553 strcpy(buffer
, "non-lazy-pointer");
4554 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(); fit
!= atom
->fixupsEnd(); ++fit
) {
4555 if ( fit
->binding
== ld::Fixup::bindingsIndirectlyBound
) {
4556 strcpy(buffer
, "non-lazy-pointer-to: ");
4557 strlcat(buffer
, state
.indirectBindingTable
[fit
->u
.bindingIndex
]->name(), 4096);
4560 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
4561 strcpy(buffer
, "non-lazy-pointer-to-local: ");
4562 strlcat(buffer
, fit
->u
.target
->name(), 4096);
4568 fprintf(mapFile
, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom
->finalAddress(), atom
->size(),
4569 readerToFileOrdinal
[atom
->file()], name
);
4575 warning("could not write map file: %s\n", _options
.generatedMapPath());
4581 // used to sort atoms with debug notes
4582 class DebugNoteSorter
4585 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
4587 // first sort by reader
4588 ld::File::Ordinal leftFileOrdinal
= left
->file()->ordinal();
4589 ld::File::Ordinal rightFileOrdinal
= right
->file()->ordinal();
4590 if ( leftFileOrdinal
!= rightFileOrdinal
)
4591 return (leftFileOrdinal
< rightFileOrdinal
);
4593 // then sort by atom objectAddress
4594 uint64_t leftAddr
= left
->finalAddress();
4595 uint64_t rightAddr
= right
->finalAddress();
4596 return leftAddr
< rightAddr
;
4601 const char* OutputFile::assureFullPath(const char* path
)
4603 if ( path
[0] == '/' )
4605 char cwdbuff
[MAXPATHLEN
];
4606 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
4608 asprintf(&result
, "%s/%s", cwdbuff
, path
);
4609 if ( result
!= NULL
)
4615 void OutputFile::synthesizeDebugNotes(ld::Internal
& state
)
4617 // -S means don't synthesize debug map
4618 if ( _options
.debugInfoStripping() == Options::kDebugInfoNone
)
4620 // make a vector of atoms that come from files compiled with dwarf debug info
4621 std::vector
<const ld::Atom
*> atomsNeedingDebugNotes
;
4622 std::set
<const ld::Atom
*> atomsWithStabs
;
4623 atomsNeedingDebugNotes
.reserve(1024);
4624 const ld::relocatable::File
* objFile
= NULL
;
4625 bool objFileHasDwarf
= false;
4626 bool objFileHasStabs
= false;
4627 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
4628 ld::Internal::FinalSection
* sect
= *sit
;
4629 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
4630 const ld::Atom
* atom
= *ait
;
4631 // no stabs for atoms that would not be in the symbol table
4632 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)
4634 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages
)
4636 if ( atom
->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel
)
4638 // no stabs for absolute symbols
4639 if ( atom
->definition() == ld::Atom::definitionAbsolute
)
4641 // no stabs for .eh atoms
4642 if ( atom
->contentType() == ld::Atom::typeCFI
)
4644 // no stabs for string literal atoms
4645 if ( atom
->contentType() == ld::Atom::typeCString
)
4647 // no stabs for kernel dtrace probes
4648 if ( (_options
.outputKind() == Options::kStaticExecutable
) && (strncmp(atom
->name(), "__dtrace_probe$", 15) == 0) )
4650 const ld::File
* file
= atom
->file();
4651 if ( file
!= NULL
) {
4652 if ( file
!= objFile
) {
4653 objFileHasDwarf
= false;
4654 objFileHasStabs
= false;
4655 objFile
= dynamic_cast<const ld::relocatable::File
*>(file
);
4656 if ( objFile
!= NULL
) {
4657 switch ( objFile
->debugInfo() ) {
4658 case ld::relocatable::File::kDebugInfoNone
:
4660 case ld::relocatable::File::kDebugInfoDwarf
:
4661 objFileHasDwarf
= true;
4663 case ld::relocatable::File::kDebugInfoStabs
:
4664 case ld::relocatable::File::kDebugInfoStabsUUID
:
4665 objFileHasStabs
= true;
4670 if ( objFileHasDwarf
)
4671 atomsNeedingDebugNotes
.push_back(atom
);
4672 if ( objFileHasStabs
)
4673 atomsWithStabs
.insert(atom
);
4678 // sort by file ordinal then atom ordinal
4679 std::sort(atomsNeedingDebugNotes
.begin(), atomsNeedingDebugNotes
.end(), DebugNoteSorter());
4681 // synthesize "debug notes" and add them to master stabs vector
4682 const char* dirPath
= NULL
;
4683 const char* filename
= NULL
;
4684 bool wroteStartSO
= false;
4685 state
.stabs
.reserve(atomsNeedingDebugNotes
.size()*4);
4686 std::unordered_set
<const char*, CStringHash
, CStringEquals
> seenFiles
;
4687 for (std::vector
<const ld::Atom
*>::iterator it
=atomsNeedingDebugNotes
.begin(); it
!= atomsNeedingDebugNotes
.end(); it
++) {
4688 const ld::Atom
* atom
= *it
;
4689 const ld::File
* atomFile
= atom
->file();
4690 const ld::relocatable::File
* atomObjFile
= dynamic_cast<const ld::relocatable::File
*>(atomFile
);
4691 //fprintf(stderr, "debug note for %s\n", atom->name());
4692 const char* newPath
= atom
->translationUnitSource();
4693 if ( newPath
!= NULL
) {
4694 const char* newDirPath
;
4695 const char* newFilename
;
4696 const char* lastSlash
= strrchr(newPath
, '/');
4697 if ( lastSlash
== NULL
)
4699 newFilename
= lastSlash
+1;
4700 char* temp
= strdup(newPath
);
4702 // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
4703 temp
[lastSlash
-newPath
+1] = '\0';
4704 // need SO's whenever the translation unit source file changes
4705 if ( (filename
== NULL
) || (strcmp(newFilename
,filename
) != 0) ) {
4706 if ( filename
!= NULL
) {
4707 // translation unit change, emit ending SO
4708 ld::relocatable::File::Stab endFileStab
;
4709 endFileStab
.atom
= NULL
;
4710 endFileStab
.type
= N_SO
;
4711 endFileStab
.other
= 1;
4712 endFileStab
.desc
= 0;
4713 endFileStab
.value
= 0;
4714 endFileStab
.string
= "";
4715 state
.stabs
.push_back(endFileStab
);
4717 // new translation unit, emit start SO's
4718 ld::relocatable::File::Stab dirPathStab
;
4719 dirPathStab
.atom
= NULL
;
4720 dirPathStab
.type
= N_SO
;
4721 dirPathStab
.other
= 0;
4722 dirPathStab
.desc
= 0;
4723 dirPathStab
.value
= 0;
4724 dirPathStab
.string
= newDirPath
;
4725 state
.stabs
.push_back(dirPathStab
);
4726 ld::relocatable::File::Stab fileStab
;
4727 fileStab
.atom
= NULL
;
4728 fileStab
.type
= N_SO
;
4732 fileStab
.string
= newFilename
;
4733 state
.stabs
.push_back(fileStab
);
4734 // Synthesize OSO for start of file
4735 ld::relocatable::File::Stab objStab
;
4736 objStab
.atom
= NULL
;
4737 objStab
.type
= N_OSO
;
4738 // <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
4739 objStab
.other
= atomFile
->cpuSubType();
4741 if ( atomObjFile
!= NULL
) {
4742 objStab
.string
= assureFullPath(atomObjFile
->debugInfoPath());
4743 objStab
.value
= atomObjFile
->debugInfoModificationTime();
4746 objStab
.string
= assureFullPath(atomFile
->path());
4747 objStab
.value
= atomFile
->modificationTime();
4749 state
.stabs
.push_back(objStab
);
4750 wroteStartSO
= true;
4751 // add the source file path to seenFiles so it does not show up in SOLs
4752 seenFiles
.insert(newFilename
);
4754 asprintf(&fullFilePath
, "%s%s", newDirPath
, newFilename
);
4755 // add both leaf path and full path
4756 seenFiles
.insert(fullFilePath
);
4758 filename
= newFilename
;
4759 dirPath
= newDirPath
;
4760 if ( atom
->section().type() == ld::Section::typeCode
) {
4761 // Synthesize BNSYM and start FUN stabs
4762 ld::relocatable::File::Stab beginSym
;
4763 beginSym
.atom
= atom
;
4764 beginSym
.type
= N_BNSYM
;
4768 beginSym
.string
= "";
4769 state
.stabs
.push_back(beginSym
);
4770 ld::relocatable::File::Stab startFun
;
4771 startFun
.atom
= atom
;
4772 startFun
.type
= N_FUN
;
4776 startFun
.string
= atom
->name();
4777 state
.stabs
.push_back(startFun
);
4778 // Synthesize any SOL stabs needed
4779 const char* curFile
= NULL
;
4780 for (ld::Atom::LineInfo::iterator lit
= atom
->beginLineInfo(); lit
!= atom
->endLineInfo(); ++lit
) {
4781 if ( lit
->fileName
!= curFile
) {
4782 if ( seenFiles
.count(lit
->fileName
) == 0 ) {
4783 seenFiles
.insert(lit
->fileName
);
4784 ld::relocatable::File::Stab sol
;
4790 sol
.string
= lit
->fileName
;
4791 state
.stabs
.push_back(sol
);
4793 curFile
= lit
->fileName
;
4796 // Synthesize end FUN and ENSYM stabs
4797 ld::relocatable::File::Stab endFun
;
4799 endFun
.type
= N_FUN
;
4804 state
.stabs
.push_back(endFun
);
4805 ld::relocatable::File::Stab endSym
;
4807 endSym
.type
= N_ENSYM
;
4812 state
.stabs
.push_back(endSym
);
4815 ld::relocatable::File::Stab globalsStab
;
4816 const char* name
= atom
->name();
4817 if ( atom
->scope() == ld::Atom::scopeTranslationUnit
) {
4818 // Synthesize STSYM stab for statics
4819 globalsStab
.atom
= atom
;
4820 globalsStab
.type
= N_STSYM
;
4821 globalsStab
.other
= 1;
4822 globalsStab
.desc
= 0;
4823 globalsStab
.value
= 0;
4824 globalsStab
.string
= name
;
4825 state
.stabs
.push_back(globalsStab
);
4828 // Synthesize GSYM stab for other globals
4829 globalsStab
.atom
= atom
;
4830 globalsStab
.type
= N_GSYM
;
4831 globalsStab
.other
= 1;
4832 globalsStab
.desc
= 0;
4833 globalsStab
.value
= 0;
4834 globalsStab
.string
= name
;
4835 state
.stabs
.push_back(globalsStab
);
4841 if ( wroteStartSO
) {
4843 ld::relocatable::File::Stab endFileStab
;
4844 endFileStab
.atom
= NULL
;
4845 endFileStab
.type
= N_SO
;
4846 endFileStab
.other
= 1;
4847 endFileStab
.desc
= 0;
4848 endFileStab
.value
= 0;
4849 endFileStab
.string
= "";
4850 state
.stabs
.push_back(endFileStab
);
4853 // copy any stabs from .o file
4854 std::set
<const ld::File
*> filesSeenWithStabs
;
4855 for (std::set
<const ld::Atom
*>::iterator it
=atomsWithStabs
.begin(); it
!= atomsWithStabs
.end(); it
++) {
4856 const ld::Atom
* atom
= *it
;
4857 objFile
= dynamic_cast<const ld::relocatable::File
*>(atom
->file());
4858 if ( objFile
!= NULL
) {
4859 if ( filesSeenWithStabs
.count(objFile
) == 0 ) {
4860 filesSeenWithStabs
.insert(objFile
);
4861 const std::vector
<ld::relocatable::File::Stab
>* stabs
= objFile
->stabs();
4862 if ( stabs
!= NULL
) {
4863 for(std::vector
<ld::relocatable::File::Stab
>::const_iterator sit
= stabs
->begin(); sit
!= stabs
->end(); ++sit
) {
4864 ld::relocatable::File::Stab stab
= *sit
;
4865 // ignore stabs associated with atoms that were dead stripped or coalesced away
4866 if ( (sit
->atom
!= NULL
) && (atomsWithStabs
.count(sit
->atom
) == 0) )
4868 // <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
4869 if ( (stab
.type
== N_SO
) && (stab
.string
!= NULL
) && (stab
.string
[0] != '\0') ) {
4872 state
.stabs
.push_back(stab
);