LoongArch: Fix relaxation overflow caused by section alignment
When deleting NOP instructions addend by .align at second pass, this may cause the PC decrease but the symbol address to remain unchanged due to section alignment. To solve this question, we subtract a maximux alignment of all sections like RISC-V.
This commit is contained in:
parent
192781a398
commit
156a2edbdb
@ -4196,7 +4196,8 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec,
|
|||||||
static bool
|
static bool
|
||||||
loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
|
loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
|
||||||
Elf_Internal_Rela *rel_hi, bfd_vma symval,
|
Elf_Internal_Rela *rel_hi, bfd_vma symval,
|
||||||
struct bfd_link_info *info, bool *again)
|
struct bfd_link_info *info, bool *again,
|
||||||
|
bfd_vma max_alignment)
|
||||||
{
|
{
|
||||||
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
||||||
Elf_Internal_Rela *rel_lo = rel_hi + 2;
|
Elf_Internal_Rela *rel_lo = rel_hi + 2;
|
||||||
@ -4212,14 +4213,22 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
|
|||||||
bfd_vma pc = sec_addr (sec) + rel_hi->r_offset;
|
bfd_vma pc = sec_addr (sec) + rel_hi->r_offset;
|
||||||
|
|
||||||
/* If pc and symbol not in the same segment, add/sub segment alignment.
|
/* If pc and symbol not in the same segment, add/sub segment alignment.
|
||||||
FIXME: if there are multiple readonly segments? */
|
FIXME: if there are multiple readonly segments? How to determine if
|
||||||
|
two sections are in the same segment. */
|
||||||
if (!(sym_sec->flags & SEC_READONLY))
|
if (!(sym_sec->flags & SEC_READONLY))
|
||||||
{
|
{
|
||||||
|
max_alignment = info->maxpagesize > max_alignment ? info->maxpagesize
|
||||||
|
: max_alignment;
|
||||||
if (symval > pc)
|
if (symval > pc)
|
||||||
pc -= info->maxpagesize;
|
pc -= max_alignment;
|
||||||
else if (symval < pc)
|
else if (symval < pc)
|
||||||
pc += info->maxpagesize;
|
pc += max_alignment;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if (symval > pc)
|
||||||
|
pc -= max_alignment;
|
||||||
|
else if (symval < pc)
|
||||||
|
pc += max_alignment;
|
||||||
|
|
||||||
const uint32_t addi_d = 0x02c00000;
|
const uint32_t addi_d = 0x02c00000;
|
||||||
const uint32_t pcaddi = 0x18000000;
|
const uint32_t pcaddi = 0x18000000;
|
||||||
@ -4360,7 +4369,8 @@ loongarch_relax_align (bfd *abfd, asection *sec,
|
|||||||
static bool
|
static bool
|
||||||
loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
|
loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
|
||||||
Elf_Internal_Rela *rel_hi, bfd_vma symval,
|
Elf_Internal_Rela *rel_hi, bfd_vma symval,
|
||||||
struct bfd_link_info *info, bool *again)
|
struct bfd_link_info *info, bool *again,
|
||||||
|
bfd_vma max_alignment)
|
||||||
{
|
{
|
||||||
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
||||||
Elf_Internal_Rela *rel_lo = rel_hi + 2;
|
Elf_Internal_Rela *rel_lo = rel_hi + 2;
|
||||||
@ -4379,11 +4389,18 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
|
|||||||
FIXME: if there are multiple readonly segments? */
|
FIXME: if there are multiple readonly segments? */
|
||||||
if (!(sym_sec->flags & SEC_READONLY))
|
if (!(sym_sec->flags & SEC_READONLY))
|
||||||
{
|
{
|
||||||
|
max_alignment = info->maxpagesize > max_alignment ? info->maxpagesize
|
||||||
|
: max_alignment;
|
||||||
if (symval > pc)
|
if (symval > pc)
|
||||||
pc -= info->maxpagesize;
|
pc -= max_alignment;
|
||||||
else if (symval < pc)
|
else if (symval < pc)
|
||||||
pc += info->maxpagesize;
|
pc += max_alignment;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
if (symval > pc)
|
||||||
|
pc -= max_alignment;
|
||||||
|
else if (symval < pc)
|
||||||
|
pc += max_alignment;
|
||||||
|
|
||||||
const uint32_t addi_d = 0x02c00000;
|
const uint32_t addi_d = 0x02c00000;
|
||||||
const uint32_t pcaddi = 0x18000000;
|
const uint32_t pcaddi = 0x18000000;
|
||||||
@ -4435,6 +4452,21 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Traverse all output sections and return the max alignment. */
|
||||||
|
|
||||||
|
static bfd_vma
|
||||||
|
loongarch_get_max_alignment (asection *sec)
|
||||||
|
{
|
||||||
|
asection *o;
|
||||||
|
unsigned int max_alignment_power = 0;
|
||||||
|
|
||||||
|
for (o = sec->output_section->owner->sections; o != NULL; o = o->next)
|
||||||
|
if (o->alignment_power > max_alignment_power)
|
||||||
|
max_alignment_power = o->alignment_power;
|
||||||
|
|
||||||
|
return (bfd_vma) 1 << max_alignment_power;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
||||||
struct bfd_link_info *info,
|
struct bfd_link_info *info,
|
||||||
@ -4445,6 +4477,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
|||||||
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
|
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
|
||||||
Elf_Internal_Rela *relocs;
|
Elf_Internal_Rela *relocs;
|
||||||
*again = false;
|
*again = false;
|
||||||
|
bfd_vma max_alignment = 0;
|
||||||
|
|
||||||
if (bfd_link_relocatable (info)
|
if (bfd_link_relocatable (info)
|
||||||
|| sec->sec_flg0
|
|| sec->sec_flg0
|
||||||
@ -4477,6 +4510,15 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
|||||||
|
|
||||||
data->relocs = relocs;
|
data->relocs = relocs;
|
||||||
|
|
||||||
|
/* Estimate the maximum alignment for all output sections once time
|
||||||
|
should be enough. */
|
||||||
|
max_alignment = htab->max_alignment;
|
||||||
|
if (max_alignment == (bfd_vma) -1)
|
||||||
|
{
|
||||||
|
max_alignment = loongarch_get_max_alignment (sec);
|
||||||
|
htab->max_alignment = max_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sec->reloc_count; i++)
|
for (unsigned int i = 0; i < sec->reloc_count; i++)
|
||||||
{
|
{
|
||||||
char symtype;
|
char symtype;
|
||||||
@ -4613,6 +4655,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
|||||||
if (1 == info->relax_pass)
|
if (1 == info->relax_pass)
|
||||||
loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
|
loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_DELETE:
|
case R_LARCH_DELETE:
|
||||||
if (1 == info->relax_pass)
|
if (1 == info->relax_pass)
|
||||||
{
|
{
|
||||||
@ -4620,6 +4663,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
|||||||
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
|
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_TLS_LE_HI20_R:
|
case R_LARCH_TLS_LE_HI20_R:
|
||||||
case R_LARCH_TLS_LE_LO12_R:
|
case R_LARCH_TLS_LE_LO12_R:
|
||||||
case R_LARCH_TLS_LE_ADD_R:
|
case R_LARCH_TLS_LE_ADD_R:
|
||||||
@ -4630,34 +4674,25 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
|
|||||||
case R_LARCH_PCALA_HI20:
|
case R_LARCH_PCALA_HI20:
|
||||||
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
||||||
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
|
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
|
||||||
info, again);
|
info, again, max_alignment);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_GOT_PC_HI20:
|
case R_LARCH_GOT_PC_HI20:
|
||||||
if (local_got && 0 == info->relax_pass
|
if (local_got && 0 == info->relax_pass
|
||||||
&& (i + 4) <= sec->reloc_count)
|
&& (i + 4) <= sec->reloc_count)
|
||||||
{
|
{
|
||||||
if (loongarch_relax_pcala_ld (abfd, sec, rel))
|
if (loongarch_relax_pcala_ld (abfd, sec, rel))
|
||||||
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
|
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
|
||||||
info, again);
|
info, again, max_alignment);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_TLS_LD_PC_HI20:
|
case R_LARCH_TLS_LD_PC_HI20:
|
||||||
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
|
||||||
loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval,
|
|
||||||
info, again);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R_LARCH_TLS_GD_PC_HI20:
|
case R_LARCH_TLS_GD_PC_HI20:
|
||||||
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
|
||||||
loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval,
|
|
||||||
info, again);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case R_LARCH_TLS_DESC_PC_HI20:
|
case R_LARCH_TLS_DESC_PC_HI20:
|
||||||
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
|
||||||
loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval,
|
loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval,
|
||||||
info, again);
|
info, again, max_alignment);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
25
ld/testsuite/ld-loongarch-elf/relax-section-align-overflow.s
Normal file
25
ld/testsuite/ld-loongarch-elf/relax-section-align-overflow.s
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# relocation overflow because .align
|
||||||
|
.text
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
# Add one NOP instruction
|
||||||
|
.align 3
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
|
||||||
|
.section ".t.a", "ax"
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
# In one try:
|
||||||
|
# first pass, la.local can be relaxed (0x120200010 - 0x120000014 = 0x1ffffc)
|
||||||
|
# second pass, the NOP addend by .align be deleted and pc decrease 4,
|
||||||
|
# but .L1 not decrease because section alignment.
|
||||||
|
# (0x120200010 - 0x120000010 = 0x200000)
|
||||||
|
la.local $t0, .L1
|
||||||
|
.fill 0x1ffff0
|
||||||
|
|
||||||
|
.section ".t.b", "ax"
|
||||||
|
.L1:
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
# To make section address not change when first .align 3 delete NOP
|
||||||
|
.align 4
|
||||||
|
addi.d $t0, $t1, 0
|
||||||
|
|
@ -268,6 +268,17 @@ if [istarget loongarch64-*-*] {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_ld_link_tests \
|
||||||
|
[list \
|
||||||
|
[list \
|
||||||
|
"loongarch relax section align overflow" \
|
||||||
|
"-e0 -Ttext 0x120000000" "" \
|
||||||
|
"" \
|
||||||
|
{relax-section-align-overflow.s} \
|
||||||
|
{} \
|
||||||
|
"relax-section-align-overflow" \
|
||||||
|
] \
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if [check_shared_lib_support] {
|
if [check_shared_lib_support] {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user