@@ -392,25 +392,26 @@ static void writeImmediateLdr(void *loc, const Ldr &ldr) {
392392// ->
393393// adr xM, _foo
394394// nop
395- static void applyAdrpAdd (uint8_t *buf, const ConcatInputSection *isec,
395+ static bool applyAdrpAdd (uint8_t *buf, const ConcatInputSection *isec,
396396 uint64_t offset1, uint64_t offset2) {
397397 uint32_t ins1 = read32le (buf + offset1);
398398 uint32_t ins2 = read32le (buf + offset2);
399399 Adrp adrp;
400400 Add add;
401401 if (!parseAdrp (ins1, adrp) || !parseAdd (ins2, add))
402- return ;
402+ return false ;
403403 if (adrp.destRegister != add.srcRegister )
404- return ;
404+ return false ;
405405
406406 uint64_t addr1 = isec->getVA () + offset1;
407407 uint64_t referent = pageBits (addr1) + adrp.addend + add.addend ;
408408 int64_t delta = referent - addr1;
409409 if (!isValidAdrOffset (delta))
410- return ;
410+ return false ;
411411
412412 writeAdr (buf + offset1, add.destRegister , delta);
413413 writeNop (buf + offset2);
414+ return true ;
414415}
415416
416417// Transforms two adrp instructions into a single adrp if their referent
@@ -495,16 +496,12 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
495496 uint64_t offset1, uint64_t offset2,
496497 uint64_t offset3) {
497498 uint32_t ins1 = read32le (buf + offset1);
498- Adrp adrp;
499- if (!parseAdrp (ins1, adrp))
500- return ;
501499 uint32_t ins2 = read32le (buf + offset2);
502- Add add;
503- if (!parseAdd (ins2, add))
504- return ;
505500 uint32_t ins3 = read32le (buf + offset3);
501+ Adrp adrp;
502+ Add add;
506503 Ldr ldr;
507- if (!parseLdr (ins3, ldr))
504+ if (!parseAdrp (ins1, adrp) || ! parseAdd (ins2, add) || ! parseLdr (ins3, ldr))
508505 return ;
509506 if (adrp.destRegister != add.srcRegister )
510507 return ;
@@ -527,18 +524,8 @@ static void applyAdrpAddLdr(uint8_t *buf, const ConcatInputSection *isec,
527524 return ;
528525 }
529526
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))
540528 return ;
541- }
542529
543530 // Move the target's page offset into the ldr's immediate offset.
544531 // adrp x0, _foo@PAGE
@@ -572,67 +559,45 @@ static void applyAdrpLdrGotLdr(uint8_t *buf, const ConcatInputSection *isec,
572559 // adrp x1, _foo@GOTPAGE
573560 // ldr x2, [x1, _foo@GOTPAGEOFF]
574561 // ldr x3, [x2, #off]
575-
576- uint32_t ins1 = read32le (buf + offset1);
577- Adrp adrp;
578- if (!parseAdrp (ins1, adrp))
579- return ;
580562 uint32_t ins3 = read32le (buf + offset3);
581563 Ldr ldr3;
582564 if (!parseLdr (ins3, ldr3))
583565 return ;
584-
585- if (ldr2.baseRegister != adrp.destRegister )
586- return ;
587566 if (ldr3.baseRegister != ldr2.destRegister )
588567 return ;
589568 // Loads from the GOT must be pointer sized.
590569 if (ldr2.p2Size != 3 || ldr2.isFloat )
591570 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);
606572 }
607573}
608574
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-
616575template <typename Callback>
617576static void forEachHint (ArrayRef<uint8_t > data, Callback callback) {
618577 std::array<uint64_t , 3 > args;
619578
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 ();
622588 if (type == 0 )
623589 break ;
624590
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+ }
626597 // 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 )
630599 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));
636601 }
637602}
638603
0 commit comments