@@ -392,25 +392,26 @@ static void writeImmediateLdr(void *loc, const Ldr &ldr) {
392
392
// ->
393
393
// adr xM, _foo
394
394
// nop
395
- static void applyAdrpAdd (uint8_t *buf, const ConcatInputSection *isec,
395
+ static bool applyAdrpAdd (uint8_t *buf, const ConcatInputSection *isec,
396
396
uint64_t offset1, uint64_t offset2) {
397
397
uint32_t ins1 = read32le (buf + offset1);
398
398
uint32_t ins2 = read32le (buf + offset2);
399
399
Adrp adrp;
400
400
Add add;
401
401
if (!parseAdrp (ins1, adrp) || !parseAdd (ins2, add))
402
- return ;
402
+ return false ;
403
403
if (adrp.destRegister != add.srcRegister )
404
- return ;
404
+ return false ;
405
405
406
406
uint64_t addr1 = isec->getVA () + offset1;
407
407
uint64_t referent = pageBits (addr1) + adrp.addend + add.addend ;
408
408
int64_t delta = referent - addr1;
409
409
if (!isValidAdrOffset (delta))
410
- return ;
410
+ return false ;
411
411
412
412
writeAdr (buf + offset1, add.destRegister , delta);
413
413
writeNop (buf + offset2);
414
+ return true ;
414
415
}
415
416
416
417
// Transforms two adrp instructions into a single adrp if their referent
@@ -495,16 +496,12 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
495
496
uint64_t offset1, uint64_t offset2,
496
497
uint64_t offset3) {
497
498
uint32_t ins1 = read32le (buf + offset1);
498
- Adrp adrp;
499
- if (!parseAdrp (ins1, adrp))
500
- return ;
501
499
uint32_t ins2 = read32le (buf + offset2);
502
- Add add;
503
- if (!parseAdd (ins2, add))
504
- return ;
505
500
uint32_t ins3 = read32le (buf + offset3);
501
+ Adrp adrp;
502
+ Add add;
506
503
Ldr ldr;
507
- if (!parseLdr (ins3, ldr))
504
+ if (!parseAdrp (ins1, adrp) || ! parseAdd (ins2, add) || ! parseLdr (ins3, ldr))
508
505
return ;
509
506
if (adrp.destRegister != add.srcRegister )
510
507
return ;
@@ -527,18 +524,8 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
527
524
return ;
528
525
}
529
526
530
- // Load the target address into a register and load from there indirectly.
531
- // adr x1, _foo
532
- // nop
533
- // ldr x2, [x1, #off]
534
- int64_t adrOffset = referent - addr1;
535
- if (isValidAdrOffset (adrOffset)) {
536
- writeAdr (buf + offset1, ldr.baseRegister , adrOffset);
537
- // Note: ld64 moves the offset into the adr instruction for AdrpAddLdr, but
538
- // not for AdrpLdrGotLdr. Its effect is the same either way.
539
- writeNop (buf + offset2);
527
+ if (applyAdrpAdd (buf, isec, offset1, offset2))
540
528
return ;
541
- }
542
529
543
530
// Move the target's page offset into the ldr's immediate offset.
544
531
// adrp x0, _foo@PAGE
@@ -572,67 +559,45 @@ static void applyAdrpLdrGotLdr(uint8_t *buf, const ConcatInputSection *isec,
572
559
// adrp x1, _foo@GOTPAGE
573
560
// ldr x2, [x1, _foo@GOTPAGEOFF]
574
561
// ldr x3, [x2, #off]
575
-
576
- uint32_t ins1 = read32le (buf + offset1);
577
- Adrp adrp;
578
- if (!parseAdrp (ins1, adrp))
579
- return ;
580
562
uint32_t ins3 = read32le (buf + offset3);
581
563
Ldr ldr3;
582
564
if (!parseLdr (ins3, ldr3))
583
565
return ;
584
-
585
- if (ldr2.baseRegister != adrp.destRegister )
586
- return ;
587
566
if (ldr3.baseRegister != ldr2.destRegister )
588
567
return ;
589
568
// Loads from the GOT must be pointer sized.
590
569
if (ldr2.p2Size != 3 || ldr2.isFloat )
591
570
return ;
592
-
593
- uint64_t addr1 = isec->getVA () + offset1;
594
- uint64_t addr2 = isec->getVA () + offset2;
595
- uint64_t referent = pageBits (addr1) + adrp.addend + ldr2.offset ;
596
- // Load the GOT entry's address directly.
597
- // nop
598
- // ldr x2, _foo@GOTPAGE + _foo@GOTPAGEOFF
599
- // ldr x3, [x2, #off]
600
- Ldr literalLdr = ldr2;
601
- literalLdr.offset = referent - addr2;
602
- if (isLiteralLdrEligible (literalLdr)) {
603
- writeNop (buf + offset1);
604
- writeLiteralLdr (buf + offset2, literalLdr);
605
- }
571
+ applyAdrpLdr (buf, isec, offset1, offset2);
606
572
}
607
573
}
608
574
609
- static uint64_t readValue (const uint8_t *&ptr, const uint8_t *end) {
610
- unsigned int n = 0 ;
611
- uint64_t value = decodeULEB128 (ptr, &n, end);
612
- ptr += n;
613
- return value;
614
- }
615
-
616
575
template <typename Callback>
617
576
static void forEachHint (ArrayRef<uint8_t > data, Callback callback) {
618
577
std::array<uint64_t , 3 > args;
619
578
620
- for (const uint8_t *p = data.begin (), *end = data.end (); p < end;) {
621
- uint64_t type = readValue (p, end);
579
+ auto readNext = [&]() -> uint64_t {
580
+ unsigned int n = 0 ;
581
+ uint64_t value = decodeULEB128 (data.data (), &n, data.end ());
582
+ data = data.drop_front (n);
583
+ return value;
584
+ };
585
+
586
+ while (!data.empty ()) {
587
+ uint64_t type = readNext ();
622
588
if (type == 0 )
623
589
break ;
624
590
625
- uint64_t argCount = readValue (p, end);
591
+ uint64_t argCount = readNext ();
592
+ for (unsigned i = 0 ; i < argCount; ++i) {
593
+ uint64_t arg = readNext ();
594
+ if (i < 3 )
595
+ args[i] = arg;
596
+ }
626
597
// All known LOH types as of 2022-09 have 3 or fewer arguments; skip others.
627
- if (argCount > 3 ) {
628
- for (unsigned i = 0 ; i < argCount; ++i)
629
- readValue (p, end);
598
+ if (argCount > 3 )
630
599
continue ;
631
- }
632
-
633
- for (unsigned i = 0 ; i < argCount; ++i)
634
- args[i] = readValue (p, end);
635
- callback (type, ArrayRef<uint64_t >(args.data (), argCount));
600
+ callback (type, ArrayRef (args.data (), argCount));
636
601
}
637
602
}
638
603
0 commit comments