@@ -3700,16 +3700,19 @@ loongarch_relax_delete_bytes (bfd *abfd,
/* Relax pcalau12i,addi.d => pcaddi. */
static bool
loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
- Elf_Internal_Rela *rel_hi, bfd_vma symval)
+ Elf_Internal_Rela *rel_hi, bfd_vma symval,
+ uint32_t align_max_deleted, uint32_t *pcnt_deleted)
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
Elf_Internal_Rela *rel_lo = rel_hi + 2;
uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset);
uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset);
uint32_t rd = pca & 0x1f;
- bfd_vma pc = sec_addr (sec) + rel_hi->r_offset;
+ bfd_vma pc = sec_addr (sec) + rel_hi->r_offset - *pcnt_deleted * 4;
const uint32_t addi_d = 0x02c00000;
const uint32_t pcaddi = 0x18000000;
+ bfd_signed_vma low = (bfd_signed_vma)(int32_t)0xffe00000;
+ bfd_signed_vma high = (bfd_signed_vma)(int32_t)0x1ffffc - align_max_deleted;
/* Is pcalau12i + addi.d insns? */
if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_PCALA_LO12)
@@ -3722,8 +3725,8 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
|| (((add >> 5) & 0x1f) != rd)
/* Can be relaxed to pcaddi? */
|| (symval & 0x3) /* 4 bytes align. */
- || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xffe00000)
- || ((bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x1ffffc))
+ || ((bfd_signed_vma)(symval - pc) < low)
+ || ((bfd_signed_vma)(symval - pc) > high))
return false;
pca = pcaddi | rd;
@@ -3734,6 +3737,7 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
R_LARCH_PCREL20_S2);
rel_lo->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info),
R_LARCH_DELETE);
+ (*pcnt_deleted) += 1;
return true;
}
@@ -3840,6 +3844,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
struct bfd_elf_section_data *data = elf_section_data (sec);
Elf_Internal_Rela *relocs;
*again = false;
+ uint32_t cnt_deleted = 0, align_max_deleted = 0;
if (bfd_link_relocatable (info)
|| sec->sec_flg0
@@ -3881,6 +3886,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
bool local_got = false;
char symtype;
struct elf_link_hash_entry *h = NULL;
+ bool relaxed = false;
if (r_symndx < symtab_hdr->sh_info)
{
@@ -3954,6 +3960,8 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
case R_LARCH_ALIGN:
if (2 == info->relax_pass)
loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
+ else if (0 == info->relax_pass)
+ align_max_deleted += rel->r_addend;
break;
case R_LARCH_DELETE:
if (info->relax_pass == 1)
@@ -3961,23 +3969,32 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
}
+ else if (0 == info->relax_pass)
+ cnt_deleted += 1;
break;
case R_LARCH_PCALA_HI20:
if (info->relax_pass == 0)
{
if (i + 4 > sec->reloc_count)
break;
- loongarch_relax_pcala_addi (abfd, sec, rel, symval);
+ relaxed = loongarch_relax_pcala_addi (abfd, sec, rel, symval,
+ align_max_deleted, &cnt_deleted);
+ /* Skip the next R_LARCH_{RELAX, PCALA_LO12, RELAX} relocs. */
+ if (relaxed)
+ i += 3;
}
break;
case R_LARCH_GOT_PC_HI20:
- if (local_got)
+ if (info->relax_pass == 0 && local_got)
{
if (i + 4 > sec->reloc_count)
break;
if (loongarch_relax_pcala_ld (abfd, sec, rel))
{
- loongarch_relax_pcala_addi (abfd, sec, rel, symval);
+ relaxed = loongarch_relax_pcala_addi (abfd, sec, rel, symval,
+ align_max_deleted, &cnt_deleted);
+ if (relaxed)
+ i += 3;
}
}
break;
new file mode 100644
@@ -0,0 +1,6 @@
+#...
+.*pcaddi.*
+.*pcalau12i.*
+.*addi.*
+.*pcaddi.*
+#pass
new file mode 100644
@@ -0,0 +1,25 @@
+ .data
+ .type obj1, @object
+obj1:
+ .word 0
+ .size obj1, .-obj1
+
+ .space 8
+
+ .type obj2, @object
+obj2:
+ .word 0
+ .size obj2, .-obj2
+
+ .text
+main:
+ la.local $a0, obj1
+ la.local $a0, obj3
+ la.local $a0, obj2
+
+ .bss
+ .space 0x4
+ .type obj3, @object
+obj3:
+ .word 0
+ .size obj3, .-obj3
new file mode 100644
@@ -0,0 +1,8 @@
+#...
+.*nop.*
+.*nop.*
+.*nop.*
+.*nop.*
+.*pcalau12i.*
+.*addi.*
+#pass
new file mode 100644
@@ -0,0 +1,15 @@
+ .text
+main:
+ nop
+ nop
+ nop
+ nop
+ .align 4
+ la.local $a0, obj1
+
+ .data
+ .space 0x10
+ .type obj1, @object
+obj1:
+ .word 0
+ .size obj1, .-obj1
@@ -43,6 +43,26 @@ if [istarget loongarch64-*-*] {
] \
"relax" \
] \
+ [list \
+ "relax-edge1" \
+ "-e 0 -Ttext 0x400000 -Tdata 0x200000 -Tbss 0x600000" "" \
+ "" \
+ {relax-edge1.s} \
+ [list \
+ [list objdump -d relax-edge1.dd] \
+ ] \
+ "relax-edge1" \
+ ] \
+ [list \
+ "relax-edge2" \
+ "-e 0 -Ttext 0x400000 -Tdata 0x600000" "" \
+ "" \
+ {relax-edge2.s} \
+ [list \
+ [list objdump -d relax-edge2.dd] \
+ ] \
+ "relax-edge2" \
+ ] \
]
set objdump_flags "-s -j .data"