diff options
author | Lulu Cai <cailulu@loongson.cn> | 2024-11-05 16:21:28 +0800 |
---|---|---|
committer | liuzhensong <liuzhensong@loongson.cn> | 2024-11-19 09:42:23 +0800 |
commit | 77bcfb741cbec8cadec7a0d450a32c8a5b161f23 (patch) | |
tree | 2c340a41d66881cf10c0b053c111124be4d4adb3 | |
parent | 0073bda2108b9d9b71a687a9fc17a3f5b455528f (diff) | |
download | binutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.zip binutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.tar.gz binutils-77bcfb741cbec8cadec7a0d450a32c8a5b161f23.tar.bz2 |
LoongArch: Do not relax pcalau12i+ld.d when there is overflow
There is no overflow check for the relaxation of pcalau12i+ld.d =>
pcalau12i+addi.d. For instruction sequences that can be relaxed,
they are directly relaxed to pcalau12i+addi.d. However, when the
relative distance between the symbol and the pc exceeds the 32-bit
range, the symbol value cannot be obtained correctly.
Adds an overflow check for the relaxation of pcalau12i+ld.d.
If it is found that the relaxation will overflow, it will not
be relaxed.
-rw-r--r-- | bfd/elfnn-loongarch.c | 32 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/check_got_relax.d | 60 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/check_got_relax.s | 43 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/check_relax_got.ld | 25 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp | 1 |
5 files changed, 156 insertions, 5 deletions
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index 608d179..8189a23 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -5099,12 +5099,12 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, /* Relax pcalau12i,ld.d => pcalau12i,addi.d. */ static bool loongarch_relax_pcala_ld (bfd *abfd, asection *sec, - asection *sym_sec ATTRIBUTE_UNUSED, + asection *sym_sec, Elf_Internal_Rela *rel_hi, - bfd_vma symval ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd_vma symval, + struct bfd_link_info *info, bool *again ATTRIBUTE_UNUSED, - bfd_vma max_alignment ATTRIBUTE_UNUSED) + bfd_vma max_alignment) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; Elf_Internal_Rela *rel_lo = rel_hi + 2; @@ -5113,10 +5113,32 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec, uint32_t rd = LARCH_GET_RD (pca); uint32_t addi_d = LARCH_OP_ADDI_D; + /* This section's output_offset need to subtract the bytes of instructions + relaxed by the previous sections, so it needs to be updated beforehand. + size_input_section already took care of updating it after relaxation, + so we additionally update once here. */ + sec->output_offset = sec->output_section->size; + bfd_vma pc = sec_addr (sec) + rel_hi->r_offset; + + /* 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 + : max_alignment; + + 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) || (LARCH_GET_RJ (ld) != rd) - || !LARCH_INSN_LD_D (ld)) + || !LARCH_INSN_LD_D (ld) + /* Within +-2G addressing range. */ + || (bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0x80000000 + || (bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x7fffffff) return false; addi_d = addi_d | (rd << 5) | rd; diff --git a/ld/testsuite/ld-loongarch-elf/check_got_relax.d b/ld/testsuite/ld-loongarch-elf/check_got_relax.d new file mode 100644 index 0000000..da00fec --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/check_got_relax.d @@ -0,0 +1,60 @@ +#ld: -T check_relax_got.ld +#objdump: -D + +.*: file format .* + + +Disassembly of section .text: + +0+10000 <_start>: + 10000: 1a03fe04 pcalau12i \$a0, 8176 + 10004: 28c06084 ld.d \$a0, \$a0, 24 + 10008: 1a03fe04 pcalau12i \$a0, 8176 + 1000c: 28c08084 ld.d \$a0, \$a0, 32 + 10010: 1a03fe04 pcalau12i \$a0, 8176 + 10014: 28c04084 ld.d \$a0, \$a0, 16 + +0+10018 <sym_default_1>: + 10018: 00000123 .word 0x00000123 + +0+1001c <sym_hidden_1>: + 1001c: 00000123 .word 0x00000123 + +0+10020 <sym_protected_1>: + 10020: 00000123 .word 0x00000123 + +Disassembly of section .got: + +0+2000000 <_GLOBAL_OFFSET_TABLE_>: + ... + 2000008: 00010018 .word 0x00010018 + 200000c: 00000000 .word 0x00000000 + 2000010: 82000020 .word 0x82000020 + 2000014: 00000000 .word 0x00000000 + 2000018: 82000018 .word 0x82000018 + 200001c: 00000000 .word 0x00000000 + 2000020: 8200001c .word 0x8200001c + 2000024: 00000000 .word 0x00000000 + 2000028: 0001001c .word 0x0001001c + 200002c: 00000000 .word 0x00000000 + 2000030: 00010020 asrtle.d \$ra, \$zero + 2000034: 00000000 .word 0x00000000 + +Disassembly of section .other: + +0+82000000 <underflow>: + 82000000: 1b000004 pcalau12i \$a0, -524288 + 82000004: 28c02084 ld.d \$a0, \$a0, 8 + 82000008: 1b000004 pcalau12i \$a0, -524288 + 8200000c: 28c0a084 ld.d \$a0, \$a0, 40 + 82000010: 1b000004 pcalau12i \$a0, -524288 + 82000014: 28c0c084 ld.d \$a0, \$a0, 48 + +0+82000018 <sym_default_2>: + 82000018: 00000456 .word 0x00000456 + +0+8200001c <sym_hidden_2>: + 8200001c: 00000456 .word 0x00000456 + +0+82000020 <sym_protected_2>: + 82000020: 00000456 .word 0x00000456 diff --git a/ld/testsuite/ld-loongarch-elf/check_got_relax.s b/ld/testsuite/ld-loongarch-elf/check_got_relax.s new file mode 100644 index 0000000..6bdf817 --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/check_got_relax.s @@ -0,0 +1,43 @@ + .text + .global _start +_start: + + # dot not relax when overflow + la.got $a0,sym_default_2 + la.got $a0,sym_hidden_2 + la.got $a0,sym_protected_2 + +sym_default_1: + .word 0x123 + + .global sym_hidden_1 + .hidden sym_hidden_1 +sym_hidden_1: + .word 0x123 + + .global sym_protected_1 + .protected sym_protected_1 +sym_protected_1: + .word 0x123 + + + .section .other,"ax",@progbits +underflow: + # dot not relax when underflow + la.got $a0,sym_default_1 + la.got $a0,sym_hidden_1 + la.got $a0,sym_protected_1 + + .global sym_default_2 +sym_default_2: + .word 0x456 + + .global sym_hidden_2 + .hidden sym_hidden_2 +sym_hidden_2: + .word 0x456 + + .global sym_protected_2 + .protected sym_protected_2 +sym_protected_2: + .word 0x456 diff --git a/ld/testsuite/ld-loongarch-elf/check_relax_got.ld b/ld/testsuite/ld-loongarch-elf/check_relax_got.ld new file mode 100644 index 0000000..287f28e --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/check_relax_got.ld @@ -0,0 +1,25 @@ +OUTPUT_ARCH(loongarch) +ENTRY(_start) +SECTIONS +{ + PROVIDE (__executable_start = 0x8000); + . = 0x10000; + .text : + { + *(.text) + } =0 + . = 0x2000000; + .got : + { + *(.got.plt) *(.got) + } + . = 0x82000000; + .other : + { + *(.other) + } + /DISCARD/ : + { + *(*) + } +} diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp index 3313f72..e1b038c 100644 --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp @@ -47,6 +47,7 @@ if [istarget "loongarch64-*-*"] { run_dump_test "tls-le-relax" run_dump_test "relax-medium-call" run_dump_test "relax-medium-call-1" + run_dump_test "check_got_relax" } if [istarget "loongarch32-*-*"] { |