@@ -469,25 +469,9 @@ void RangeExtensionThunk<E>::copy_buf(Context<E> &ctx) {
469469#define ASSERT_RANGE (val, start, size ) \
470470 assert ((start) <= (val) && (val) < ((start) + (size)))
471471
472- static void relax_adrp_ldr_got_ldr (Context<E> &ctx, ObjectFile<E> *file,
473- std::string_view &hints) {
474- i64 addr1 = read_uleb (hints);
475- i64 addr2 = read_uleb (hints);
476- i64 addr3 = read_uleb (hints);
477-
478- Subsection<E> *subsec = file->find_subsection (ctx, addr1);
479- if (!subsec || !subsec->is_alive )
480- return ;
481-
482- ASSERT_RANGE (addr1, subsec->input_addr , subsec->input_size );
483- ASSERT_RANGE (addr2, subsec->input_addr , subsec->input_size );
484- ASSERT_RANGE (addr3, subsec->input_addr , subsec->input_size );
485-
486- i64 offset1 = addr1 - subsec->input_addr ;
487- i64 offset2 = addr2 - subsec->input_addr ;
488- i64 offset3 = addr3 - subsec->input_addr ;
489-
490- u8 *loc = ctx.buf + subsec->isec .osec .hdr .offset + subsec->output_offset ;
472+ static void relax_adrp_ldr_got_ldr (Context<E> &ctx, Subsection<E> &subsec,
473+ i64 offset1, i64 offset2, i64 offset3) {
474+ u8 *loc = ctx.buf + subsec.isec .osec .hdr .offset + subsec.output_offset ;
491475 ul32 *loc1 = (ul32 *)(loc + offset1);
492476 ul32 *loc2 = (ul32 *)(loc + offset2);
493477 ul32 *loc3 = (ul32 *)(loc + offset3);
@@ -501,9 +485,9 @@ static void relax_adrp_ldr_got_ldr(Context<E> &ctx, ObjectFile<E> *file,
501485 (*loc2 & 0xffc0'0000 ) != 0xf940'0000 )
502486 return ;
503487
504- u64 got_addr = page (subsec-> get_addr (ctx) + offset1) +
505- (bits (*loc1, 23 , 5 ) << 14 ) + (bits (*loc1, 30 , 29 ) << 12 ) +
506- (bits (*loc2, 21 , 10 ) << 3 );
488+ u64 got_addr = page (subsec. get_addr (ctx) + offset1) +
489+ (bits (*loc1, 23 , 5 ) << 14 ) + (bits (*loc1, 30 , 29 ) << 12 ) +
490+ (bits (*loc2, 21 , 10 ) << 3 );
507491
508492 ASSERT_RANGE (got_addr, ctx.got .hdr .addr , ctx.got .hdr .size );
509493
@@ -516,7 +500,7 @@ static void relax_adrp_ldr_got_ldr(Context<E> &ctx, ObjectFile<E> *file,
516500 switch (*loc3 & 0xffc0'0000 ) {
517501 case 0xf940'0000 : { // ldr Xc, [Xb, #imm]
518502 u64 imm = bits (*loc3, 21 , 10 ) * 8 ;
519- i64 disp = got_value + imm - subsec-> get_addr (ctx) - offset3;
503+ i64 disp = got_value + imm - subsec. get_addr (ctx) - offset3;
520504 if (disp == sign_extend (disp, 20 ) && (disp & 0b11 ) == 0 ) {
521505 *loc1 = 0xd503'201f ; // nop
522506 *loc2 = 0xd503'201f ; // nop
@@ -527,7 +511,7 @@ static void relax_adrp_ldr_got_ldr(Context<E> &ctx, ObjectFile<E> *file,
527511 }
528512 case 0xb940'0000 : { // ldr Wc, [Xb, #imm]
529513 u64 imm = bits (*loc3, 21 , 10 ) * 4 ;
530- i64 disp = got_value + imm - subsec-> get_addr (ctx) - offset3;
514+ i64 disp = got_value + imm - subsec. get_addr (ctx) - offset3;
531515 if (disp == sign_extend (disp, 20 ) && (disp & 0b11 ) == 0 ) {
532516 *loc1 = 0xd503'201f ; // nop
533517 *loc2 = 0xd503'201f ; // nop
@@ -540,30 +524,17 @@ static void relax_adrp_ldr_got_ldr(Context<E> &ctx, ObjectFile<E> *file,
540524 }
541525
542526 // If the GOT slot is close enough to PC, we can eliminate ADRP.
543- if (i64 disp = got_addr - subsec-> get_addr (ctx) - offset2;
527+ if (i64 disp = got_addr - subsec. get_addr (ctx) - offset2;
544528 disp == sign_extend (disp, 20 ) && (disp & 0b11 ) == 0 ) {
545529 *loc1 = 0xd503'201f ; // nop
546530 *loc2 = 0x5800'0000 | (bits (disp, 20 , 2 ) << 5 ) |
547531 bits (*loc2, 4 , 0 ); // ldr Xb, _foo@GOT
548532 }
549533}
550534
551- static void relax_adrp_add (Context<E> &ctx, ObjectFile<E> *file,
552- std::string_view &hints) {
553- i64 addr1 = read_uleb (hints);
554- i64 addr2 = read_uleb (hints);
555-
556- Subsection<E> *subsec = file->find_subsection (ctx, addr1);
557- if (!subsec || !subsec->is_alive )
558- return ;
559-
560- ASSERT_RANGE (addr1, subsec->input_addr , subsec->input_size );
561- ASSERT_RANGE (addr2, subsec->input_addr , subsec->input_size );
562-
563- i64 offset1 = addr1 - subsec->input_addr ;
564- i64 offset2 = addr2 - subsec->input_addr ;
565-
566- u8 *loc = ctx.buf + subsec->isec .osec .hdr .offset + subsec->output_offset ;
535+ static void relax_adrp_add (Context<E> &ctx, Subsection<E> &subsec,
536+ i64 offset1, i64 offset2) {
537+ u8 *loc = ctx.buf + subsec.isec .osec .hdr .offset + subsec.output_offset ;
567538 ul32 *loc1 = (ul32 *)(loc + offset1);
568539 ul32 *loc2 = (ul32 *)(loc + offset2);
569540
@@ -575,10 +546,10 @@ static void relax_adrp_add(Context<E> &ctx, ObjectFile<E> *file,
575546 (*loc2 & 0xffc0'0000 ) != 0x9100'0000 )
576547 return ;
577548
578- u64 addr = page (subsec-> get_addr (ctx) + offset1) +
579- (bits (*loc1, 23 , 5 ) << 14 ) + (bits (*loc1, 30 , 29 ) << 12 ) +
580- bits (*loc2, 21 , 10 );
581- i64 disp = addr - subsec-> get_addr (ctx) - offset2;
549+ u64 addr = page (subsec. get_addr (ctx) + offset1) +
550+ (bits (*loc1, 23 , 5 ) << 14 ) + (bits (*loc1, 30 , 29 ) << 12 ) +
551+ bits (*loc2, 21 , 10 );
552+ i64 disp = addr - subsec. get_addr (ctx) - offset2;
582553
583554 if (disp == sign_extend (disp, 20 )) {
584555 *loc1 = 0xd503'201f ; // nop
@@ -618,12 +589,45 @@ void apply_linker_optimization_hints(Context<E> &ctx) {
618589 i64 nargs = read_uleb (hints);
619590
620591 switch (type) {
621- case LOH_ARM64_ADRP_LDR_GOT_LDR:
622- relax_adrp_ldr_got_ldr (ctx, file, hints);
592+ case LOH_ARM64_ADRP_LDR_GOT_LDR: {
593+ assert (nargs == 3 );
594+ i64 addr1 = read_uleb (hints);
595+ i64 addr2 = read_uleb (hints);
596+ i64 addr3 = read_uleb (hints);
597+
598+ Subsection<E> *subsec = file->find_subsection (ctx, addr1);
599+ if (!subsec || !subsec->is_alive )
600+ return ;
601+
602+ ASSERT_RANGE (addr1, subsec->input_addr , subsec->input_size );
603+ ASSERT_RANGE (addr2, subsec->input_addr , subsec->input_size );
604+ ASSERT_RANGE (addr3, subsec->input_addr , subsec->input_size );
605+
606+ i64 offset1 = addr1 - subsec->input_addr ;
607+ i64 offset2 = addr2 - subsec->input_addr ;
608+ i64 offset3 = addr3 - subsec->input_addr ;
609+
610+ relax_adrp_ldr_got_ldr (ctx, *subsec, offset1, offset2, offset3);
623611 break ;
624- case LOH_ARM64_ADRP_ADD:
625- relax_adrp_add (ctx, file, hints);
612+ }
613+ case LOH_ARM64_ADRP_ADD: {
614+ assert (nargs == 2 );
615+ i64 addr1 = read_uleb (hints);
616+ i64 addr2 = read_uleb (hints);
617+
618+ Subsection<E> *subsec = file->find_subsection (ctx, addr1);
619+ if (!subsec || !subsec->is_alive )
620+ return ;
621+
622+ ASSERT_RANGE (addr1, subsec->input_addr , subsec->input_size );
623+ ASSERT_RANGE (addr2, subsec->input_addr , subsec->input_size );
624+
625+ i64 offset1 = addr1 - subsec->input_addr ;
626+ i64 offset2 = addr2 - subsec->input_addr ;
627+
628+ relax_adrp_add (ctx, *subsec, offset1, offset2);
626629 break ;
630+ }
627631 default :
628632 // Skip unsupported optimizations hints.
629633 for (i64 i = 0 ; i < nargs; i++)
0 commit comments