1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
30 #include <libkern/OSByteOrder.h>
35 #include "MachOFileAbstraction.hpp"
37 #include "branch_island.h"
41 namespace branch_island
{
44 static std::map
<const Atom
*, uint64_t> sAtomToAddress
;
47 struct TargetAndOffset
{ const ld::Atom
* atom
; uint32_t offset
; };
48 class TargetAndOffsetComparor
51 bool operator()(const TargetAndOffset
& left
, const TargetAndOffset
& right
) const
53 if ( left
.atom
!= right
.atom
)
54 return ( left
.atom
< right
.atom
);
55 return ( left
.offset
< right
.offset
);
60 static bool _s_log
= false;
61 static ld::Section
_s_text_section("__TEXT", "__text", ld::Section::typeCode
);
64 #if SUPPORT_ARCH_arm64
66 class ARM64BranchIslandAtom
: public ld::Atom
{
68 ARM64BranchIslandAtom(const char* nm
, const ld::Atom
* target
, TargetAndOffset finalTarget
)
69 : ld::Atom(_s_text_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
70 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
71 ld::Atom::symbolTableIn
, false, false, false, ld::Atom::Alignment(2)),
73 _fixup1(0, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressARM64Branch26
, target
),
74 _fixup2(0, ld::Fixup::k1of1
, ld::Fixup::kindIslandTarget
, finalTarget
.atom
) {
75 if (_s_log
) fprintf(stderr
, "%p: ARM64 branch island to final target %s\n",
76 this, finalTarget
.atom
->name());
79 virtual const ld::File
* file() const { return NULL
; }
80 virtual const char* name() const { return _name
; }
81 virtual uint64_t size() const { return 4; }
82 virtual uint64_t objectAddress() const { return 0; }
83 virtual void copyRawContent(uint8_t buffer
[]) const {
84 OSWriteLittleInt32(buffer
, 0, 0x14000000);
86 virtual void setScope(Scope
) { }
87 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixup1
; }
88 virtual ld::Fixup::iterator
fixupsEnd() const { return &((ld::Fixup
*)&_fixup2
)[1]; }
98 class ARMtoARMBranchIslandAtom
: public ld::Atom
{
100 ARMtoARMBranchIslandAtom(const char* nm
, const ld::Atom
* target
, TargetAndOffset finalTarget
)
101 : ld::Atom(_s_text_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
102 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
103 ld::Atom::symbolTableIn
, false, false, false, ld::Atom::Alignment(2)),
105 _fixup1(0, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressARMBranch24
, target
),
106 _fixup2(0, ld::Fixup::k1of1
, ld::Fixup::kindIslandTarget
, finalTarget
.atom
) {
107 if (_s_log
) fprintf(stderr
, "%p: ARM-to-ARM branch island to final target %s\n",
108 this, finalTarget
.atom
->name());
111 virtual const ld::File
* file() const { return NULL
; }
112 virtual const char* name() const { return _name
; }
113 virtual uint64_t size() const { return 4; }
114 virtual uint64_t objectAddress() const { return 0; }
115 virtual void copyRawContent(uint8_t buffer
[]) const {
116 OSWriteLittleInt32(buffer
, 0, 0xEA000000);
118 virtual void setScope(Scope
) { }
119 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixup1
; }
120 virtual ld::Fixup::iterator
fixupsEnd() const { return &((ld::Fixup
*)&_fixup2
)[1]; }
130 class ARMtoThumb1BranchIslandAtom
: public ld::Atom
{
132 ARMtoThumb1BranchIslandAtom(const char* nm
, const ld::Atom
* target
, TargetAndOffset finalTarget
)
133 : ld::Atom(_s_text_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
134 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
135 ld::Atom::symbolTableIn
, false, false, false, ld::Atom::Alignment(2)),
137 _finalTarget(finalTarget
) {
138 if (_s_log
) fprintf(stderr
, "%p: ARM-to-thumb1 branch island to final target %s\n",
139 this, finalTarget
.atom
->name());
142 virtual const ld::File
* file() const { return NULL
; }
143 virtual const char* name() const { return _name
; }
144 virtual uint64_t size() const { return 16; }
145 virtual uint64_t objectAddress() const { return 0; }
146 virtual void copyRawContent(uint8_t buffer
[]) const {
147 // There is no large displacement thumb1 branch instruction.
148 // Instead use ARM instructions that can jump to thumb.
149 // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
150 int64_t displacement
= _finalTarget
.atom
->finalAddress() + _finalTarget
.offset
- (this->finalAddress() + 12);
151 if ( _finalTarget
.atom
->isThumb() )
153 OSWriteLittleInt32(&buffer
[ 0], 0, 0xe59fc004); // ldr ip, pc + 4
154 OSWriteLittleInt32(&buffer
[ 4], 0, 0xe08fc00c); // add ip, pc, ip
155 OSWriteLittleInt32(&buffer
[ 8], 0, 0xe12fff1c); // bx ip
156 OSWriteLittleInt32(&buffer
[12], 0, displacement
); // .long target-this
158 virtual void setScope(Scope
) { }
162 TargetAndOffset _finalTarget
;
167 class Thumb2toThumbBranchIslandAtom
: public ld::Atom
{
169 Thumb2toThumbBranchIslandAtom(const char* nm
, const ld::Atom
* target
, TargetAndOffset finalTarget
)
170 : ld::Atom(_s_text_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
171 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
172 ld::Atom::symbolTableIn
, false, true, false, ld::Atom::Alignment(1)),
174 _fixup1(0, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressThumbBranch22
, target
),
175 _fixup2(0, ld::Fixup::k1of1
, ld::Fixup::kindIslandTarget
, finalTarget
.atom
) {
176 if (_s_log
) fprintf(stderr
, "%p: Thumb-to-thumb branch island to final target %s\n",
177 this, finalTarget
.atom
->name());
180 virtual const ld::File
* file() const { return NULL
; }
181 virtual const char* name() const { return _name
; }
182 virtual uint64_t size() const { return 4; }
183 virtual uint64_t objectAddress() const { return 0; }
184 virtual void copyRawContent(uint8_t buffer
[]) const {
185 OSWriteLittleInt32(buffer
, 0, 0xf0008000);
187 virtual void setScope(Scope
) { }
188 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixup1
; }
189 virtual ld::Fixup::iterator
fixupsEnd() const { return &((ld::Fixup
*)&_fixup2
)[1]; }
199 class Thumb2toThumbBranchAbsoluteIslandAtom
: public ld::Atom
{
201 Thumb2toThumbBranchAbsoluteIslandAtom(const char* nm
, const ld::Section
& inSect
, TargetAndOffset finalTarget
)
202 : ld::Atom(inSect
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
203 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
204 ld::Atom::symbolTableIn
, false, true, false, ld::Atom::Alignment(1)),
206 _fixup1(0, ld::Fixup::k1of2
, ld::Fixup::kindSetTargetAddress
, finalTarget
.atom
),
207 _fixup2(0, ld::Fixup::k2of2
, ld::Fixup::kindStoreThumbLow16
),
208 _fixup3(4, ld::Fixup::k1of2
, ld::Fixup::kindSetTargetAddress
, finalTarget
.atom
),
209 _fixup4(4, ld::Fixup::k2of2
, ld::Fixup::kindStoreThumbHigh16
),
210 _fixup5(0, ld::Fixup::k1of1
, ld::Fixup::kindIslandTarget
, finalTarget
.atom
) {
211 if (_s_log
) fprintf(stderr
, "%p: Thumb-to-thumb absolute branch island to final target %s\n",
212 this, finalTarget
.atom
->name());
215 virtual const ld::File
* file() const { return NULL
; }
216 virtual const char* name() const { return _name
; }
217 virtual uint64_t size() const { return 10; }
218 virtual uint64_t objectAddress() const { return 0; }
219 virtual void copyRawContent(uint8_t buffer
[]) const {
220 OSWriteLittleInt32(&buffer
[0], 0, 0x0c00f240); // movw r12, #0x5678
221 OSWriteLittleInt32(&buffer
[4], 0, 0x0c00f2c0); // movt r12, #0x1234
222 OSWriteLittleInt16(&buffer
[8], 0, 0x4760); // bx r12
224 virtual void setScope(Scope
) { }
225 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixup1
; }
226 virtual ld::Fixup::iterator
fixupsEnd() const { return &((ld::Fixup
*)&_fixup5
)[1]; }
239 class NoPicARMtoThumbMBranchIslandAtom
: public ld::Atom
{
241 NoPicARMtoThumbMBranchIslandAtom(const char* nm
, const ld::Atom
* target
, TargetAndOffset finalTarget
)
242 : ld::Atom(_s_text_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
243 ld::Atom::scopeLinkageUnit
, ld::Atom::typeBranchIsland
,
244 ld::Atom::symbolTableIn
, false, false, false, ld::Atom::Alignment(2)),
246 _finalTarget(finalTarget
) {
247 if (_s_log
) fprintf(stderr
, "%p: NoPIC ARM-to-Thumb branch island to final target %s\n",
248 this, finalTarget
.atom
->name());
251 virtual const ld::File
* file() const { return NULL
; }
252 virtual const char* name() const { return _name
; }
253 virtual uint64_t size() const { return 8; }
254 virtual uint64_t objectAddress() const { return 0; }
255 virtual void copyRawContent(uint8_t buffer
[]) const {
256 // There is no large displacement thumb1 branch instruction.
257 // Instead use ARM instructions that can jump to thumb.
258 // we use a 32-bit displacement, so we can directly jump to final target which means no island hopping
259 uint32_t targetAddr
= _finalTarget
.atom
->finalAddress();
260 if ( _finalTarget
.atom
->isThumb() )
262 OSWriteLittleInt32(&buffer
[0], 0, 0xe51ff004); // ldr pc, [pc, #-4]
263 OSWriteLittleInt32(&buffer
[4], 0, targetAddr
); // .long target-this
265 virtual void setScope(Scope
) { }
269 TargetAndOffset _finalTarget
;
273 static ld::Atom
* makeBranchIsland(const Options
& opts
, ld::Fixup::Kind kind
, int islandRegion
, const ld::Atom
* nextTarget
,
274 TargetAndOffset finalTarget
, const ld::Section
& inSect
, bool crossSectionBranch
)
277 if ( finalTarget
.offset
== 0 ) {
278 if ( islandRegion
== 0 )
279 asprintf(&name
, "%s.island", finalTarget
.atom
->name());
281 asprintf(&name
, "%s.island.%d", finalTarget
.atom
->name(), islandRegion
+1);
284 asprintf(&name
, "%s_plus_%d.island.%d", finalTarget
.atom
->name(), finalTarget
.offset
, islandRegion
);
288 case ld::Fixup::kindStoreARMBranch24
:
289 case ld::Fixup::kindStoreThumbBranch22
:
290 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
291 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
292 if ( crossSectionBranch
&& opts
.preferSubArchitecture() && opts
.archSupportsThumb2() ) {
293 return new Thumb2toThumbBranchAbsoluteIslandAtom(name
, inSect
, finalTarget
);
295 else if ( finalTarget
.atom
->isThumb() ) {
296 if ( opts
.preferSubArchitecture() && opts
.archSupportsThumb2() ) {
297 return new Thumb2toThumbBranchIslandAtom(name
, nextTarget
, finalTarget
);
299 else if ( opts
.outputSlidable() ) {
300 return new ARMtoThumb1BranchIslandAtom(name
, nextTarget
, finalTarget
);
303 return new NoPicARMtoThumbMBranchIslandAtom(name
, nextTarget
, finalTarget
);
307 return new ARMtoARMBranchIslandAtom(name
, nextTarget
, finalTarget
);
310 #if SUPPORT_ARCH_arm64
311 case ld::Fixup::kindStoreARM64Branch26
:
312 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
313 return new ARM64BranchIslandAtom(name
, nextTarget
, finalTarget
);
317 assert(0 && "unexpected branch kind");
324 static uint64_t textSizeWhenMightNeedBranchIslands(const Options
& opts
, bool seenThumbBranch
)
326 switch ( opts
.architecture() ) {
328 if ( ! seenThumbBranch
)
329 return 32000000; // ARM can branch +/- 32MB
330 else if ( opts
.preferSubArchitecture() && opts
.archSupportsThumb2() )
331 return 16000000; // thumb2 can branch +/- 16MB
333 return 4000000; // thumb1 can branch +/- 4MB
335 #if SUPPORT_ARCH_arm64
337 return 128000000; // arm64 can branch +/- 128MB
341 assert(0 && "unexpected architecture");
342 return 0x100000000LL
;
346 static uint64_t maxDistanceBetweenIslands(const Options
& opts
, bool seenThumbBranch
)
348 switch ( opts
.architecture() ) {
350 if ( ! seenThumbBranch
)
351 return 30*1024*1024; // 2MB of branch islands per 32MB
352 else if ( opts
.preferSubArchitecture() && opts
.archSupportsThumb2() )
353 return 14*1024*1024; // 2MB of branch islands per 16MB
355 return 3500000; // 0.5MB of branch islands per 4MB
357 #if SUPPORT_ARCH_arm64
359 return 124*1024*1024; // 4MB of branch islands per 128MB
363 assert(0 && "unexpected architecture");
364 return 0x100000000LL
;
369 // PowerPC can do PC relative branches as far as +/-16MB.
370 // If a branch target is >16MB then we insert one or more
371 // "branch islands" between the branch and its target that
372 // allows island hopping to the target.
374 // Branch Island Algorithm
376 // If the __TEXT segment < 16MB, then no branch islands needed
377 // Otherwise, every 14MB into the __TEXT segment a region is
378 // added which can contain branch islands. Every out-of-range
379 // bl instruction is checked. If it crosses a region, an island
380 // is added to that region with the same target and the bl is
381 // adjusted to target the island instead.
383 // In theory, if too many islands are added to one region, it
384 // could grow the __TEXT enough that other previously in-range
385 // bl branches could be pushed out of range. We reduce the
386 // probability this could happen by placing the ranges every
387 // 14MB which means the region would have to be 2MB (512,000 islands)
388 // before any branches could be pushed out of range.
392 static void makeIslandsForSection(const Options
& opts
, ld::Internal
& state
, ld::Internal::FinalSection
* textSection
, unsigned stubCount
)
394 // assign section offsets to each atom in __text section, watch for thumb branches, and find total size
395 bool hasThumbBranches
= false;
396 bool haveCrossSectionBranches
= false;
397 const bool preload
= (opts
.outputKind() == Options::kPreload
);
399 for (std::vector
<const ld::Atom
*>::iterator ait
=textSection
->atoms
.begin(); ait
!= textSection
->atoms
.end(); ++ait
) {
400 const ld::Atom
* atom
= *ait
;
401 // check for thumb branches and cross section branches
402 const ld::Atom
* target
= NULL
;
403 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
404 if ( fit
->firstInCluster() ) {
407 switch ( fit
->binding
) {
408 case ld::Fixup::bindingNone
:
409 case ld::Fixup::bindingByNameUnbound
:
411 case ld::Fixup::bindingByContentBound
:
412 case ld::Fixup::bindingDirectlyBound
:
413 target
= fit
->u
.target
;
415 case ld::Fixup::bindingsIndirectlyBound
:
416 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
419 bool haveBranch
= false;
421 case ld::Fixup::kindStoreThumbBranch22
:
422 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
423 hasThumbBranches
= true;
424 // fall into arm branch case
425 case ld::Fixup::kindStoreARMBranch24
:
426 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
432 if ( haveBranch
&& (target
->contentType() != ld::Atom::typeStub
) ) {
433 // <rdar://problem/14792124> haveCrossSectionBranches only applies to -preload builds
434 if ( preload
&& (atom
->section() != target
->section()) )
435 haveCrossSectionBranches
= true;
439 ld::Atom::Alignment atomAlign
= atom
->alignment();
440 uint64_t atomAlignP2
= (1 << atomAlign
.powerOf2
);
441 uint64_t currentModulus
= (offset
% atomAlignP2
);
442 if ( currentModulus
!= atomAlign
.modulus
) {
443 if ( atomAlign
.modulus
> currentModulus
)
444 offset
+= atomAlign
.modulus
-currentModulus
;
446 offset
+= atomAlign
.modulus
+atomAlignP2
-currentModulus
;
448 (const_cast<ld::Atom
*>(atom
))->setSectionOffset(offset
);
449 offset
+= atom
->size();
451 uint64_t totalTextSize
= offset
+ stubCount
*16;
452 if ( (totalTextSize
< textSizeWhenMightNeedBranchIslands(opts
, hasThumbBranches
)) && !haveCrossSectionBranches
)
454 if (_s_log
) fprintf(stderr
, "ld: section %s size=%llu, might need branch islands\n", textSection
->sectionName(), totalTextSize
);
456 // Figure out how many regions of branch islands will be needed, and their locations.
457 // Construct a vector containing the atoms after which branch islands will be inserted,
458 // taking into account follow on fixups. No atom run without an island can exceed kBetweenRegions.
459 const uint64_t kBetweenRegions
= maxDistanceBetweenIslands(opts
, hasThumbBranches
); // place regions of islands every 14MB in __text section
460 std::vector
<const ld::Atom
*> branchIslandInsertionPoints
; // atoms in the atom list after which branch islands will be inserted
461 uint64_t previousIslandEndAddr
= 0;
462 const ld::Atom
*insertionPoint
= NULL
;
463 branchIslandInsertionPoints
.reserve(totalTextSize
/kBetweenRegions
*2);
464 for (std::vector
<const ld::Atom
*>::iterator it
=textSection
->atoms
.begin(); it
!= textSection
->atoms
.end(); it
++) {
465 const ld::Atom
* atom
= *it
;
466 // if we move past the next atom, will the run length exceed kBetweenRegions?
467 if ( atom
->sectionOffset() + atom
->size() > previousIslandEndAddr
+ kBetweenRegions
) {
468 // yes. Add the last known good location (atom) for inserting a branch island.
469 if ( insertionPoint
== NULL
)
470 throwf("Unable to insert branch island. No insertion point available.");
471 branchIslandInsertionPoints
.push_back(insertionPoint
);
472 previousIslandEndAddr
= insertionPoint
->sectionOffset()+insertionPoint
->size();
473 insertionPoint
= NULL
;
475 // Can we insert an island after this atom? If so then keep track of it.
476 if ( !atom
->hasFixupsOfKind(ld::Fixup::kindNoneFollowOn
) )
477 insertionPoint
= atom
;
479 // add one more island after the last atom if close to limit
480 if ( (insertionPoint
!= NULL
) && (insertionPoint
->sectionOffset() + insertionPoint
->size() > previousIslandEndAddr
+ (kBetweenRegions
-0x100000)) )
481 branchIslandInsertionPoints
.push_back(insertionPoint
);
482 if ( haveCrossSectionBranches
&& branchIslandInsertionPoints
.empty() ) {
483 branchIslandInsertionPoints
.push_back(textSection
->atoms
.back());
485 const int kIslandRegionsCount
= branchIslandInsertionPoints
.size();
487 if (_s_log
) fprintf(stderr
, "ld: will use %u branch island regions\n", kIslandRegionsCount
);
488 typedef std::map
<TargetAndOffset
,const ld::Atom
*, TargetAndOffsetComparor
> AtomToIsland
;
489 AtomToIsland
* regionsMap
[kIslandRegionsCount
];
490 uint64_t regionAddresses
[kIslandRegionsCount
];
491 std::vector
<const ld::Atom
*>* regionsIslands
[kIslandRegionsCount
];
492 for(int i
=0; i
< kIslandRegionsCount
; ++i
) {
493 regionsMap
[i
] = new AtomToIsland();
494 regionsIslands
[i
] = new std::vector
<const ld::Atom
*>();
495 regionAddresses
[i
] = branchIslandInsertionPoints
[i
]->sectionOffset() + branchIslandInsertionPoints
[i
]->size();
496 if (_s_log
) fprintf(stderr
, "ld: branch islands will be inserted at 0x%08llX after %s\n", regionAddresses
[i
], branchIslandInsertionPoints
[i
]->name());
498 unsigned int islandCount
= 0;
500 // create islands for branches in __text that are out of range
501 for (std::vector
<const ld::Atom
*>::iterator ait
=textSection
->atoms
.begin(); ait
!= textSection
->atoms
.end(); ++ait
) {
502 const ld::Atom
* atom
= *ait
;
503 const ld::Atom
* target
= NULL
;
505 ld::Fixup
* fixupWithTarget
= NULL
;
506 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
507 if ( fit
->firstInCluster() ) {
509 fixupWithTarget
= NULL
;
512 switch ( fit
->binding
) {
513 case ld::Fixup::bindingNone
:
514 case ld::Fixup::bindingByNameUnbound
:
516 case ld::Fixup::bindingByContentBound
:
517 case ld::Fixup::bindingDirectlyBound
:
518 target
= fit
->u
.target
;
519 fixupWithTarget
= fit
;
521 case ld::Fixup::bindingsIndirectlyBound
:
522 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
523 fixupWithTarget
= fit
;
526 bool haveBranch
= false;
528 case ld::Fixup::kindAddAddend
:
529 addend
= fit
->u
.addend
;
531 case ld::Fixup::kindStoreARMBranch24
:
532 case ld::Fixup::kindStoreThumbBranch22
:
533 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
534 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
535 #if SUPPORT_ARCH_arm64
536 case ld::Fixup::kindStoreARM64Branch26
:
537 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
545 bool crossSectionBranch
= ( preload
&& (atom
->section() != target
->section()) );
546 int64_t srcAddr
= atom
->sectionOffset() + fit
->offsetInAtom
;
547 int64_t dstAddr
= target
->sectionOffset() + addend
;
549 srcAddr
= sAtomToAddress
[atom
] + fit
->offsetInAtom
;
550 dstAddr
= sAtomToAddress
[target
] + addend
;
552 if ( target
->section().type() == ld::Section::typeStub
)
553 dstAddr
= totalTextSize
;
554 int64_t displacement
= dstAddr
- srcAddr
;
555 TargetAndOffset finalTargetAndOffset
= { target
, (uint32_t)addend
};
556 const int64_t kBranchLimit
= kBetweenRegions
;
557 if ( crossSectionBranch
&& ((displacement
> kBranchLimit
) || (displacement
< (-kBranchLimit
))) ) {
558 const ld::Atom
* island
;
559 AtomToIsland
* region
= regionsMap
[0];
560 AtomToIsland::iterator pos
= region
->find(finalTargetAndOffset
);
561 if ( pos
== region
->end() ) {
562 island
= makeBranchIsland(opts
, fit
->kind
, 0, target
, finalTargetAndOffset
, atom
->section(), true);
563 (*region
)[finalTargetAndOffset
] = island
;
564 if (_s_log
) fprintf(stderr
, "added absolute branching island %p %s, displacement=%lld\n",
565 island
, island
->name(), displacement
);
567 regionsIslands
[0]->push_back(island
);
568 state
.atomToSection
[island
] = textSection
;
571 island
= pos
->second
;
573 if (_s_log
) fprintf(stderr
, "using island %p %s for branch to %s from %s\n", island
, island
->name(), target
->name(), atom
->name());
574 fixupWithTarget
->u
.target
= island
;
575 fixupWithTarget
->binding
= ld::Fixup::bindingDirectlyBound
;
577 else if ( displacement
> kBranchLimit
) {
578 // create forward branch chain
579 const ld::Atom
* nextTarget
= target
;
580 if (_s_log
) fprintf(stderr
, "need forward branching island srcAdr=0x%08llX, dstAdr=0x%08llX, target=%s\n",
581 srcAddr
, dstAddr
, target
->name());
582 for (int i
=kIslandRegionsCount
-1; i
>=0 ; --i
) {
583 AtomToIsland
* region
= regionsMap
[i
];
584 int64_t islandRegionAddr
= regionAddresses
[i
];
585 if ( (srcAddr
< islandRegionAddr
) && ((islandRegionAddr
<= dstAddr
)) ) {
586 AtomToIsland::iterator pos
= region
->find(finalTargetAndOffset
);
587 if ( pos
== region
->end() ) {
588 ld::Atom
* island
= makeBranchIsland(opts
, fit
->kind
, i
, nextTarget
, finalTargetAndOffset
, atom
->section(), false);
589 (*region
)[finalTargetAndOffset
] = island
;
590 if (_s_log
) fprintf(stderr
, "added forward branching island %p %s to region %d for %s\n", island
, island
->name(), i
, atom
->name());
591 regionsIslands
[i
]->push_back(island
);
592 state
.atomToSection
[island
] = textSection
;
597 nextTarget
= pos
->second
;
601 if (_s_log
) fprintf(stderr
, "using island %p %s for branch to %s from %s\n", nextTarget
, nextTarget
->name(), target
->name(), atom
->name());
602 fixupWithTarget
->u
.target
= nextTarget
;
603 fixupWithTarget
->binding
= ld::Fixup::bindingDirectlyBound
;
605 else if ( displacement
< (-kBranchLimit
) ) {
606 // create back branching chain
607 const ld::Atom
* prevTarget
= target
;
608 for (int i
=0; i
< kIslandRegionsCount
; ++i
) {
609 AtomToIsland
* region
= regionsMap
[i
];
610 int64_t islandRegionAddr
= regionAddresses
[i
];
611 if ( (dstAddr
< islandRegionAddr
) && (islandRegionAddr
<= srcAddr
) ) {
612 if (_s_log
) fprintf(stderr
, "need backward branching island srcAdr=0x%08llX, dstAdr=0x%08llX, target=%s\n", srcAddr
, dstAddr
, target
->name());
613 AtomToIsland::iterator pos
= region
->find(finalTargetAndOffset
);
614 if ( pos
== region
->end() ) {
615 ld::Atom
* island
= makeBranchIsland(opts
, fit
->kind
, i
, prevTarget
, finalTargetAndOffset
, atom
->section(), false);
616 (*region
)[finalTargetAndOffset
] = island
;
617 if (_s_log
) fprintf(stderr
, "added back branching island %p %s to region %d for %s\n", island
, island
->name(), i
, atom
->name());
618 regionsIslands
[i
]->push_back(island
);
619 state
.atomToSection
[island
] = textSection
;
624 prevTarget
= pos
->second
;
628 if (_s_log
) fprintf(stderr
, "using back island %p %s for %s\n", prevTarget
, prevTarget
->name(), atom
->name());
629 fixupWithTarget
->u
.target
= prevTarget
;
630 fixupWithTarget
->binding
= ld::Fixup::bindingDirectlyBound
;
637 // insert islands into __text section and adjust section offsets
638 if ( islandCount
> 0 ) {
639 if ( _s_log
) fprintf(stderr
, "ld: %u branch islands required in %u regions\n", islandCount
, kIslandRegionsCount
);
640 std::vector
<const ld::Atom
*> newAtomList
;
641 newAtomList
.reserve(textSection
->atoms
.size()+islandCount
);
644 for (std::vector
<const ld::Atom
*>::iterator ait
=textSection
->atoms
.begin(); ait
!= textSection
->atoms
.end(); ait
++) {
645 const ld::Atom
* atom
= *ait
;
646 newAtomList
.push_back(atom
);
647 if ( (regionIndex
< kIslandRegionsCount
) && (atom
== branchIslandInsertionPoints
[regionIndex
]) ) {
648 std::vector
<const ld::Atom
*>* islands
= regionsIslands
[regionIndex
];
649 newAtomList
.insert(newAtomList
.end(), islands
->begin(), islands
->end());
653 // swap in new list of atoms for __text section
654 textSection
->atoms
.clear();
655 textSection
->atoms
= newAtomList
;
661 static void buildAddressMap(const Options
& opts
, ld::Internal
& state
) {
662 // Assign addresses to sections
663 state
.setSectionSizesAndAlignments();
664 state
.assignFileOffsets();
666 // Assign addresses to atoms in a side table
667 const bool log
= false;
668 if ( log
) fprintf(stderr
, "buildAddressMap()\n");
669 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
= state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
670 ld::Internal::FinalSection
* sect
= *sit
;
671 uint16_t maxAlignment
= 0;
673 if ( log
) fprintf(stderr
, " section=%s/%s, address=0x%08llX\n", sect
->segmentName(), sect
->sectionName(), sect
->address
);
674 for (std::vector
<const ld::Atom
*>::iterator ait
= sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
675 const ld::Atom
* atom
= *ait
;
676 uint32_t atomAlignmentPowerOf2
= atom
->alignment().powerOf2
;
677 uint32_t atomModulus
= atom
->alignment().modulus
;
678 if ( atomAlignmentPowerOf2
> maxAlignment
)
679 maxAlignment
= atomAlignmentPowerOf2
;
680 // calculate section offset for this atom
681 uint64_t alignment
= 1 << atomAlignmentPowerOf2
;
682 uint64_t currentModulus
= (offset
% alignment
);
683 uint64_t requiredModulus
= atomModulus
;
684 if ( currentModulus
!= requiredModulus
) {
685 if ( requiredModulus
> currentModulus
)
686 offset
+= requiredModulus
-currentModulus
;
688 offset
+= requiredModulus
+alignment
-currentModulus
;
691 if ( log
) fprintf(stderr
, " 0x%08llX atom=%p, name=%s\n", sect
->address
+offset
, atom
, atom
->name());
692 sAtomToAddress
[atom
] = sect
->address
+ offset
;
694 offset
+= atom
->size();
701 void doPass(const Options
& opts
, ld::Internal
& state
)
703 // only make branch islands in final linked images
704 if ( opts
.outputKind() == Options::kObjectFile
)
707 // Allow user to disable branch island generation
708 if ( !opts
.allowBranchIslands() )
711 // only ARM[64] needs branch islands
712 switch ( opts
.architecture() ) {
714 #if SUPPORT_ARCH_arm64
722 if ( opts
.outputKind() == Options::kPreload
) {
723 buildAddressMap(opts
, state
);
726 // scan sections for number of stubs
727 unsigned stubCount
= 0;
728 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
729 ld::Internal::FinalSection
* sect
= *sit
;
730 if ( sect
->type() == ld::Section::typeStub
)
731 stubCount
= sect
->atoms
.size();
734 // scan sections and add island to each code section
735 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
736 ld::Internal::FinalSection
* sect
= *sit
;
737 if ( sect
->type() == ld::Section::typeCode
)
738 makeIslandsForSection(opts
, state
, sect
, stubCount
);
743 } // namespace branch_island
744 } // namespace passes