[PATCH v2] LoongArch: Allow to relax instructions into NOPs after handling alignment
mengqinggang
mengqinggang@loongson.cn
Fri Jul 4 03:51:23 GMT 2025
ping.
在 2025/7/1 16:05, mengqinggang 写道:
>
> 在 2025/6/30 下午5:47, WANG Xuerui 写道:
>> From: WANG Xuerui <git@xen0n.name>
>>
>> Right now, LoongArch linker relaxation is 2-pass, since after alignment
>> is done, byte deletion can no longer happen. However, as the alignment
>> pass also shrinks text sections, new relaxation chances may well be
>> created after alignment is done. Although at this point we can no longer
>> delete unused instructions without disturbing alignment, we can still
>> replace them with NOPs; popular LoongArch micro-architectures can
>> eliminate NOPs during execution, so we can expect a (very) slight
>> performance improvement from those late-created relaxation chances.
>>
>> To achieve this, the number of relax passes is raised to 3 for
>> LoongArch, and every relaxation handler except loongarch_relax_align is
>> migrated to a new helper loongarch_relax_delete_or_nop, that either
>> deletes bytes or fills the bytes to be "deleted" with NOPs, depending on
>> whether the containing section already has undergone alignment. Also,
>> since no byte can be deleted during this relax pass, in the pass the
>> pending_delete_ops structure is no longer allocated, and
>> loongarch_calc_relaxed_addr(x) degrades to the trivial "return x" in
>> this case.
>>
>> In addition, previously when calculating distances to symbols, an
>> extra segment alignment must be considered, because alignment may
>> increase distance between sites. However in the newly added 3rd pass
>> code size can no longer increase for "closed" sections, so we can skip
>> the adjustment for them to allow for a few more relaxation chances.
>>
>> A simple way to roughly measure this change's effectiveness is to check
>> how many pcalau12i + addi.d pairs are relaxed into pcaddi's. Taking a
>> Firefox 140.0.2 test build of mine as an example:
>>
>> Before: 47842 pcaddi's in libxul.so
>> After: 48089
>>
>> This is a 0.5% increase, which is kind of acceptable for a peephole
>> optimization like this; of which 9 are due to the "relax"ed symbol
>> distance treatment.
>>
>> Signed-off-by: WANG Xuerui <git@xen0n.name>
>> ---
>>
>> Changes from v1:
>>
>> - No longer adjust max_alignment when calculating distances between
>> symbols in different segments during relax pass 2 (3rd pass);
>> suggested by Ruoyao.
>> - Improved comments and the test case.
>>
>> bfd/elfnn-loongarch.c | 202 ++++++++++++------
>> ld/emultempl/loongarchelf.em | 2 +-
>> .../ld-loongarch-elf/ld-loongarch-elf.exp | 1 +
>> .../ld-loongarch-elf/relax-after-alignment.d | 30 +++
>> .../ld-loongarch-elf/relax-after-alignment.s | 49 +++++
>> 5 files changed, 219 insertions(+), 65 deletions(-)
>> create mode 100644
>> ld/testsuite/ld-loongarch-elf/relax-after-alignment.d
>> create mode 100644
>> ld/testsuite/ld-loongarch-elf/relax-after-alignment.s
>>
>> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
>> index a480a709897..b0fcfbf8db2 100644
>> --- a/bfd/elfnn-loongarch.c
>> +++ b/bfd/elfnn-loongarch.c
>> @@ -173,6 +173,10 @@ loongarch_elf_new_section_hook (bfd *abfd,
>> asection *sec)
>> #define loongarch_elf_hash_table(p) \
>> ((struct loongarch_elf_link_hash_table *) ((p)->hash)) \
>> +/* During linker relaxation, indicates whether the section has
>> already
>> + undergone alignment processing and no more byte deletion is
>> possible. */
>
>
> How about changing possible to permission?
>
>
>> +#define loongarch_sec_closed_for_deletion(sec) ((sec)->sec_flg0)
>> +
>> #define MINUS_ONE ((bfd_vma) 0 - 1)
>> #define sec_addr(sec) ((sec)->output_section->vma +
>> (sec)->output_offset)
>> @@ -4789,7 +4793,10 @@ loongarch_calc_relaxed_addr (struct
>> bfd_link_info *info, bfd_vma offset)
>> struct pending_delete_op *op;
>> splay_tree_node node;
>> - BFD_ASSERT (pdops != NULL);
>> + if (!pdops)
>> + /* Currently this means we are past the stages where byte
>> deletion could
>> + possibly happen. */
>> + return offset;
>> /* Find the op that starts just before the given address. */
>> node = splay_tree_predecessor (pdops, (splay_tree_key)offset);
>> @@ -4814,9 +4821,9 @@ loongarch_calc_relaxed_addr (struct
>> bfd_link_info *info, bfd_vma offset)
>> static void
>> loongarch_relax_delete_bytes (bfd *abfd,
>> - bfd_vma addr,
>> - size_t count,
>> - struct bfd_link_info *link_info)
>> + bfd_vma addr,
>> + size_t count,
>> + struct bfd_link_info *link_info)
>> {
>> struct loongarch_elf_link_hash_table *htab
>> = loongarch_elf_hash_table (link_info);
>> @@ -4867,6 +4874,34 @@ loongarch_relax_delete_bytes (bfd *abfd,
>> }
>> }
>> +static void
>> +loongarch_relax_delete_or_nop (bfd *abfd,
>> + asection *sec,
>> + bfd_vma addr,
>> + size_t count,
>> + struct bfd_link_info *link_info)
>> +{
>> + struct bfd_elf_section_data *data = elf_section_data (sec);
>> + bfd_byte *contents = data->this_hdr.contents;
>> +
>> + BFD_ASSERT (count % 4 == 0);
>> +
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + {
>> + /* Deletions are still possible within the section. */
>> + loongarch_relax_delete_bytes (abfd, addr, count, link_info);
>> + return;
>> + }
>> +
>> + /* We can no longer delete bytes in the section after enforcing
>> alignment.
>> + But as the resulting shrinkage may open up a few more
>> relaxation chances,
>> + allowing unnecessary instructions to be replaced with NOPs
>> instead of
>> + being removed altogether may still benefit performance to a lesser
>> + extent. */
>> + for (; count; addr += 4, count -= 4)
>> + bfd_put (32, abfd, LARCH_NOP, contents + addr);
>> +}
>> +
>> static void
>> loongarch_relax_perform_deletes (bfd *abfd, asection *sec,
>> struct bfd_link_info *link_info)
>> @@ -5135,7 +5170,7 @@ loongarch_tls_perform_trans (bfd *abfd,
>> asection *sec,
>> bfd_put (32, abfd, LARCH_NOP, contents + rel->r_offset);
>> /* link with -relax option will delete NOP. */
>> if (!info->disable_target_specific_optimizations)
>> - loongarch_relax_delete_bytes (abfd, rel->r_offset, 4, info);
>> + loongarch_relax_delete_or_nop (abfd, sec, rel->r_offset, 4,
>> info);
>> return true;
>> case R_LARCH_TLS_IE_PC_HI20:
>> @@ -5250,7 +5285,7 @@ loongarch_relax_tls_le (bfd *abfd, asection
>> *sec, asection *sym_sec,
>> if (symval < 0x800)
>> {
>> rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
>> - loongarch_relax_delete_bytes (abfd, rel->r_offset,
>> + loongarch_relax_delete_or_nop (abfd, sec, rel->r_offset,
>> 4, link_info);
>> }
>> break;
>> @@ -5275,8 +5310,8 @@ loongarch_relax_tls_le (bfd *abfd, asection
>> *sec, asection *sym_sec,
>> case R_LARCH_TLS_LE64_LO20:
>> case R_LARCH_TLS_LE64_HI12:
>> rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
>> - loongarch_relax_delete_bytes (abfd, rel->r_offset,
>> - 4, link_info);
>> + loongarch_relax_delete_or_nop (abfd, sec, rel->r_offset,
>> + 4, link_info);
>> break;
>> case R_LARCH_TLS_LE_LO12:
>> @@ -5339,17 +5374,22 @@ loongarch_relax_pcala_addi (bfd *abfd,
>> asection *sec, asection *sym_sec,
>> symval = sec_addr (sec)
>> + loongarch_calc_relaxed_addr (info, symval - sec_addr
>> (sec));
>> - /* If pc and symbol not in the same segment, add/sub segment
>> alignment. */
>> - if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> - sec->output_section,
>> - sym_sec->output_section))
>> - max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> + /* If pc and symbol not in the same segment, add/sub segment
>> alignment if the
>> + section has not undergone alignment processing because
>> distances may grow
>> + after alignment. */
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + {
>> + if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> + sec->output_section,
>> + sym_sec->output_section))
>> + max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>
>
> Need a indent, similar places below.
>
>
>> : max_alignment;
>> - if (symval > pc)
>> - pc -= (max_alignment > 4 ? max_alignment : 0);
>> - else if (symval < pc)
>> - pc += (max_alignment > 4 ? max_alignment : 0);
>> + if (symval > pc)
>> + pc -= (max_alignment > 4 ? max_alignment : 0);
>> + else if (symval < pc)
>> + pc += (max_alignment > 4 ? max_alignment : 0);
>> + }
>> const uint32_t pcaddi = LARCH_OP_PCADDI;
>> @@ -5376,7 +5416,7 @@ loongarch_relax_pcala_addi (bfd *abfd,
>> asection *sec, asection *sym_sec,
>> R_LARCH_PCREL20_S2);
>> rel_lo->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
>> - loongarch_relax_delete_bytes (abfd, rel_lo->r_offset, 4, info);
>> + loongarch_relax_delete_or_nop (abfd, sec, rel_lo->r_offset, 4, info);
>> return true;
>> }
>> @@ -5404,17 +5444,22 @@ loongarch_relax_call36 (bfd *abfd, asection
>> *sec, asection *sym_sec,
>> symval = sec_addr (sec)
>> + loongarch_calc_relaxed_addr (info, symval - sec_addr
>> (sec));
>> - /* If pc and symbol not in the same segment, add/sub segment
>> alignment. */
>> - if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> - sec->output_section,
>> - sym_sec->output_section))
>> - max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> + /* If pc and symbol not in the same segment, add/sub segment
>> alignment if the
>> + section has not undergone alignment processing because
>> distances may grow
>> + after alignment. */
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + {
>> + if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> + sec->output_section,
>> + sym_sec->output_section))
>> + max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> : max_alignment;
>> - if (symval > pc)
>> - pc -= (max_alignment > 4 ? max_alignment : 0);
>> - else if (symval < pc)
>> - pc += (max_alignment > 4 ? max_alignment : 0);
>> + if (symval > pc)
>> + pc -= (max_alignment > 4 ? max_alignment : 0);
>> + else if (symval < pc)
>> + pc += (max_alignment > 4 ? max_alignment : 0);
>> + }
>> /* Is pcalau12i + addi.d insns? */
>> if (!LARCH_INSN_JIRL (jirl)
>> @@ -5436,7 +5481,7 @@ loongarch_relax_call36 (bfd *abfd, asection
>> *sec, asection *sym_sec,
>> /* Adjust relocations. */
>> rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_LARCH_B26);
>> /* Delete jirl instruction. */
>> - loongarch_relax_delete_bytes (abfd, rel->r_offset + 4, 4, info);
>> + loongarch_relax_delete_or_nop (abfd, sec, rel->r_offset + 4, 4,
>> info);
>> return true;
>> }
>> @@ -5468,17 +5513,22 @@ loongarch_relax_pcala_ld (bfd *abfd,
>> asection *sec,
>> symval = sec_addr (sec)
>> + loongarch_calc_relaxed_addr (info, symval - sec_addr
>> (sec));
>> - /* If pc and symbol not in the same segment, add/sub segment
>> alignment. */
>> - if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> - sec->output_section,
>> - sym_sec->output_section))
>> - max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> + /* If pc and symbol not in the same segment, add/sub segment
>> alignment if the
>> + section has not undergone alignment processing because
>> distances may grow
>> + after alignment. */
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + {
>> + if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> + sec->output_section,
>> + sym_sec->output_section))
>> + max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> : max_alignment;
>> - if (symval > pc)
>> - pc -= (max_alignment > 4 ? max_alignment : 0);
>> - else if (symval < pc)
>> - pc += (max_alignment > 4 ? max_alignment : 0);
>> + if (symval > pc)
>> + pc -= (max_alignment > 4 ? max_alignment : 0);
>> + else if (symval < pc)
>> + pc += (max_alignment > 4 ? max_alignment : 0);
>> + }
>> if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12)
>> || (LARCH_GET_RD (ld) != rd)
>> @@ -5511,8 +5561,9 @@ bfd_elfNN_loongarch_set_data_segment_info
>> (struct bfd_link_info *info,
>> loongarch_elf_hash_table (info)->data_segment_phase =
>> data_segment_phase;
>> }
>> -/* Implement R_LARCH_ALIGN by deleting excess alignment NOPs.
>> - Once we've handled an R_LARCH_ALIGN, we can't relax anything
>> else. */
>> +/* Honor R_LARCH_ALIGN requests by deleting excess alignment NOPs.
>> + Once we've handled an R_LARCH_ALIGN, we can't relax anything else
>> by deleting
>> + bytes, or alignment will be disrupted. */
>> static bool
>> loongarch_relax_align (bfd *abfd, asection *sec, asection *sym_sec,
>> Elf_Internal_Rela *rel,
>> @@ -5553,9 +5604,9 @@ loongarch_relax_align (bfd *abfd, asection
>> *sec, asection *sym_sec,
>> return false;
>> }
>> - /* Once we've handled an R_LARCH_ALIGN in a section,
>> - we can't relax anything else in this section. */
>> - sec->sec_flg0 = true;
>> + /* Once we've handled an R_LARCH_ALIGN in a section, we can't
>> relax anything
>> + else by deleting bytes, or alignment will be disrupted. */
>> + loongarch_sec_closed_for_deletion (sec) = true;
>> rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
>> /* If skipping more bytes than the specified maximum,
>> @@ -5600,17 +5651,22 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd,
>> asection *sec, asection *sym_sec,
>> symval = sec_addr (sec)
>> + loongarch_calc_relaxed_addr (info, symval - sec_addr
>> (sec));
>> - /* If pc and symbol not in the same segment, add/sub segment
>> alignment. */
>> - if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> - sec->output_section,
>> - sym_sec->output_section))
>> - max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> + /* If pc and symbol not in the same segment, add/sub segment
>> alignment if the
>> + section has not undergone alignment processing because
>> distances may grow
>> + after alignment. */
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + {
>> + if (!loongarch_two_sections_in_same_segment (info->output_bfd,
>> + sec->output_section,
>> + sym_sec->output_section))
>> + max_alignment = info->maxpagesize > max_alignment ?
>> info->maxpagesize
>> : max_alignment;
>> - if (symval > pc)
>> - pc -= (max_alignment > 4 ? max_alignment : 0);
>> - else if (symval < pc)
>> - pc += (max_alignment > 4 ? max_alignment : 0);
>> + if (symval > pc)
>> + pc -= (max_alignment > 4 ? max_alignment : 0);
>> + else if (symval < pc)
>> + pc += (max_alignment > 4 ? max_alignment : 0);
>> + }
>> const uint32_t pcaddi = LARCH_OP_PCADDI;
>> @@ -5653,7 +5709,7 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd,
>> asection *sec, asection *sym_sec,
>> }
>> rel_lo->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
>> - loongarch_relax_delete_bytes (abfd, rel_lo->r_offset, 4, info);
>> + loongarch_relax_delete_or_nop (abfd, sec, rel_lo->r_offset, 4, info);
>> return true;
>> }
>> @@ -5697,15 +5753,25 @@ loongarch_elf_relax_section (bfd *abfd,
>> asection *sec,
>> if (htab->layout_mutating_for_relr)
>> return true;
>> + /* Definition of LoongArch linker relaxation passes:
>> +
>> + - Pass 0: relaxes everything except R_LARCH_ALIGN, byte
>> deletions are
>> + performed; skipped if disable_target_specific_optimizations.
>> + - Pass 1: handles alignment, byte deletions are performed.
>> Sections with
>> + R_LARCH_ALIGN relocations are marked closed for further byte
>> + deletion in order to not disturb alignment. This pass is NOT
>> + skipped even if disable_target_specific_optimizations is
>> true.
>> + - Pass 2: identical to Pass 0, but replacing relaxed insns with
>> NOP in case
>> + the containing section is closed for deletion; skip
>> condition
>> + also same as Pass 0. */
>> + bool is_alignment_pass = info->relax_pass == 1;
>> if (bfd_link_relocatable (info)
>> - || sec->sec_flg0
>> || sec->reloc_count == 0
>> || (sec->flags & SEC_RELOC) == 0
>> || (sec->flags & SEC_HAS_CONTENTS) == 0
>> /* The exp_seg_relro_adjust is enum phase_enum (0x4). */
>> || *(htab->data_segment_phase) == 4
>> - || (info->disable_target_specific_optimizations
>> - && info->relax_pass == 0))
>> + || (info->disable_target_specific_optimizations &&
>> !is_alignment_pass))
>> return true;
>> struct bfd_elf_section_data *data = elf_section_data (sec);
>> @@ -5741,7 +5807,10 @@ loongarch_elf_relax_section (bfd *abfd,
>> asection *sec,
>> htab->max_alignment = max_alignment;
>> }
>> - splay_tree pdops = pending_delete_ops_new (abfd);
>> + splay_tree pdops = NULL;
>> + if (!loongarch_sec_closed_for_deletion (sec))
>> + pdops = pending_delete_ops_new (abfd);
>> +
>> htab->pending_delete_ops = pdops;
>> for (unsigned int i = 0; i < sec->reloc_count; i++)
>> @@ -5783,7 +5852,13 @@ loongarch_elf_relax_section (bfd *abfd,
>> asection *sec,
>> }
>> relax_func_t relax_func = NULL;
>> - if (info->relax_pass == 0)
>> + if (is_alignment_pass)
>> + {
>> + if (r_type != R_LARCH_ALIGN)
>> + continue;
>> + relax_func = loongarch_relax_align;
>> + }
>> + else
>> {
>> switch (r_type)
>> {
>> @@ -5837,10 +5912,6 @@ loongarch_elf_relax_section (bfd *abfd,
>> asection *sec,
>> continue;
>> }
>> }
>> - else if (info->relax_pass == 1 && r_type == R_LARCH_ALIGN)
>> - relax_func = loongarch_relax_align;
>> - else
>> - continue;
>> /* Four kind of relocations:
>> Normal: symval is the symbol address.
>> @@ -5979,9 +6050,12 @@ loongarch_elf_relax_section (bfd *abfd,
>> asection *sec,
>> info, again, max_alignment);
>> }
>> - loongarch_relax_perform_deletes (abfd, sec, info);
>> - htab->pending_delete_ops = NULL;
>> - splay_tree_delete (pdops);
>> + if (pdops)
>> + {
>> + loongarch_relax_perform_deletes (abfd, sec, info);
>> + htab->pending_delete_ops = NULL;
>> + splay_tree_delete (pdops);
>> + }
>> return true;
>> }
>> diff --git a/ld/emultempl/loongarchelf.em b/ld/emultempl/loongarchelf.em
>> index 928fd83ab15..517ece16105 100644
>> --- a/ld/emultempl/loongarchelf.em
>> +++ b/ld/emultempl/loongarchelf.em
>> @@ -58,7 +58,7 @@ larch_elf_before_allocation (void)
>> ENABLE_RELAXATION;
>> }
>> - link_info.relax_pass = 2;
>> + link_info.relax_pass = 3;
>> }
>> static void
>> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
>> b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
>> index 2f09a69befb..e23cdc87161 100644
>> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
>> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
>> @@ -45,6 +45,7 @@ if [istarget "loongarch64-*-*"] {
>> run_dump_test "underflow_s_5_20"
>> run_dump_test "tls-le-norelax"
>> run_dump_test "tls-le-relax"
>> + run_dump_test "relax-after-alignment"
>> run_dump_test "relax-medium-call"
>> run_dump_test "relax-medium-call-1"
>> run_dump_test "check_got_relax"
>> diff --git a/ld/testsuite/ld-loongarch-elf/relax-after-alignment.d
>> b/ld/testsuite/ld-loongarch-elf/relax-after-alignment.d
>> new file mode 100644
>> index 00000000000..844c518e9c7
>> --- /dev/null
>> +++ b/ld/testsuite/ld-loongarch-elf/relax-after-alignment.d
>> @@ -0,0 +1,30 @@
>> +#name: additional relaxation chances after alignment processing
>> +#as:
>> +#ld: --defsym _start=0
>> +#objdump: -d --no-show-raw-insn
>> +
>> +.*:\s+file format .*
>> +
>> +
>> +Disassembly of section \.text:
>> +
>> +0000000120000400 <before>:
>> +\s*120000400:\s+pcalau12i\s+\$t0, 512
>> +\s*[0-9a-f]+:\s+addi\.d\s+\$t0, \$t0, 1024
>> +\s*[0-9a-f]+:\s+pcaddi\s+\$t0, 524286
>> +\s*[0-9a-f]+:\s+nop\s*
>> +\s*\.\.\.
>> +\s*120000c00:\s+pcaddi\s+\$t0, 523776
>> +\s*\.\.\.
>> +
>> +0000000120200400 <target>:
>> +\s*120200400:\s+break\s+0x0
>> +
>> +0000000120200404 <after>:
>> +\s*\.\.\.
>> +\s*1203ffbfc:\s+pcaddi\s+\$t0, -523775
>> +\s*\.\.\.
>> +\s*120400400:\s+pcaddi\s+\$t0, -524288
>> +\s*[0-9a-f]+:\s+nop\s*
>> +\s*[0-9a-f]+:\s+pcalau12i\s+\$t0, -512
>> +\s*[0-9a-f]+:\s+addi\.d\s+\$t0, \$t0, 1024
>> diff --git a/ld/testsuite/ld-loongarch-elf/relax-after-alignment.s
>> b/ld/testsuite/ld-loongarch-elf/relax-after-alignment.s
>> new file mode 100644
>> index 00000000000..24d29ecb257
>> --- /dev/null
>> +++ b/ld/testsuite/ld-loongarch-elf/relax-after-alignment.s
>> @@ -0,0 +1,49 @@
>> +# 0x0 pre-relax, 0x400 post-relax
>> +# all addresses are additionally offset by 0x120000000 without `ld
>> -shared`
>> +before:
>> + la.pcrel $t0, target # too far; should stay as pcalau12i + addi.d
>> + la.pcrel $t0, target # furthest reach of relax pass 2
>> +
>> +# 0x10 pre-relax, 0x410 post-relax
>> +.rept 508
>> +.word 0
>> +.endr
>> +
>> +# 0x800 {pre,post}-relax
>> +# 255 nops + R_LARCH_ALIGN before relaxation
>> +# none of the aligning nops should remain after relax pass 1
>> +.p2align 10
>> +
>> +# 0xbfc pre-relax, 0xc00 post-relax
>> + la.pcrel $t0, target # should become single pcaddi in relax pass 0
>> +
>> +# 0xc04 {pre,post}-relax
>> +.rept 523775
>> +.word 0
>> +.endr
>> +
>> +# 0x200400 {pre,post}-relax
>> +target:
>> + break 0
>> +
>> +# 0x200404 {pre,post}-relax
>> +after:
>> +.rept 523774
>> +.word 0
>> +.endr
>> +
>> +# 0x3ffbfc {pre,post}-relax
>> + la.pcrel $t0, target # should become single pcaddi in relax pass 0
>> +
>> +# 255 nops + R_LARCH_ALIGN before relaxation
>> +# none of the aligning nops should remain after relax pass 1
>> +.p2align 10
>> +
>> +# 0x400000 pre-relax, 0x3ffc00 post-relax
>> +.rept 512
>> +.word 0
>> +.endr
>> +
>> +# 0x400800 pre-relax, 0x400400 post-relax
>> + la.pcrel $t0, target # furthest reach of relax pass 2
>> + la.pcrel $t0, target # too far; should stay as pcalau12i + addi.d
More information about the Binutils
mailing list