@@ -222,6 +222,10 @@ loongarch_elf_new_section_hook (bfd *abfd, asection *sec)
|| (R_TYPE) == R_LARCH_TLS_LE64_LO20 \
|| (R_TYPE) == R_LARCH_TLS_LE64_HI12)
+#define IS_CALL_RELOC(R_TYPE) \
+ ((R_TYPE) == R_LARCH_B26 \
+ || (R_TYPE) == R_LARCH_CALL36)
+
/* If TLS GD/IE need dynamic relocations, INDX will be the dynamic indx,
and set NEED_RELOC to true used in allocate_dynrelocs and
loongarch_elf_relocate_section for TLS GD/IE. */
@@ -5277,6 +5281,33 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
return true;
}
+/* Delete the call undefweak instruction without plt entries when relax
+ is enabled, otherwise it will be converted to nop. */
+static bool
+loongarch_relax_call_undefweak (bfd *abfd, asection *sec,
+ Elf_Internal_Rela *rel,
+ struct bfd_link_info *info,
+ bool with_relax_reloc)
+{
+ bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
+ unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
+
+ bfd_put (32, abfd, LARCH_NOP, contents + rel->r_offset);
+ /* Medium call uses pcaddu18i + jirl, so jirl also needs
+ to be converted to nop. */
+ if (r_type == R_LARCH_CALL36)
+ bfd_put (32, abfd, LARCH_NOP, contents + rel->r_offset + 4);
+
+ if (with_relax_reloc && !info->disable_target_specific_optimizations)
+ {
+ loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
+ if (r_type == R_LARCH_CALL36)
+ loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
+ }
+ rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+ return true;
+}
+
/* Traverse all output sections and return the max alignment. */
static bfd_vma
@@ -5398,6 +5429,24 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
r_type = ELFNN_R_TYPE (rel->r_info);
}
+ /* The undefweak symbol value of non-default visibility is 0
+ and does not use plt entry, and will not be relocated in
+ the relocate_secion function. As a result, an infinite loop
+ is generated because bl %plt(sym) => bl 0. */
+ if (h != NULL
+ && h->root.type == bfd_link_hash_undefweak
+ && !h->needs_plt
+ && IS_CALL_RELOC (r_type))
+ {
+ bool with_relax_reloc = false;
+ if (i + 1 != sec->reloc_count
+ && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX)
+ with_relax_reloc = true;
+
+ loongarch_relax_call_undefweak (abfd, sec, rel, info,
+ with_relax_reloc);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+ }
relax_func_t relax_func = NULL;
if (info->relax_pass == 0)
{
@@ -853,7 +853,8 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
|| BFD_RELOC_LARCH_TLS_LE_LO12 == reloc_type
|| BFD_RELOC_LARCH_TLS_LE64_LO20 == reloc_type
|| BFD_RELOC_LARCH_TLS_LE64_HI12 == reloc_type
- || BFD_RELOC_LARCH_CALL36 == reloc_type))
+ || BFD_RELOC_LARCH_CALL36 == reloc_type
+ || BFD_RELOC_LARCH_B26 == reloc_type))
{
ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_RELAX;
ip->reloc_info[ip->reloc_num].value = const_0;
@@ -9,5 +9,6 @@ Disassembly of section .text:
.* <.text>:
[ ]+0:[ ]+50000000[ ]+b[ ]+0[ ]+# 0x0
[ ]+0: R_LARCH_B26[ ]+.L1
+[ ]+0: R_LARCH_RELAX[ ]+\*ABS\*
[ ]+4:[ ]+5800018d[ ]+beq[ ]+\$t0, \$t1, 0[ ]+# 0x4
[ ]+4: R_LARCH_B16[ ]+.L1
@@ -25,8 +25,10 @@ Disassembly of section .text:
[ ]+20:[ ]+4c000080[ ]+jr[ ]+\$a0
[ ]+24:[ ]+53ffdfff[ ]+b[ ]+-36[ ]+#[ ]+0[ ]+<\.L1>
[ ]+24:[ ]+R_LARCH_B26[ ]+\.L1
+[ ]+24:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+28:[ ]+57ffdbff[ ]+bl[ ]+-40[ ]+#[ ]+0[ ]+<\.L1>
[ ]+28:[ ]+R_LARCH_B26[ ]+\.L1
+[ ]+28:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+2c:[ ]+5bffd485[ ]+beq[ ]+\$a0,[ ]+\$a1,[ ]+-44[ ]+#[ ]+0[ ]+<\.L1>
[ ]+2c:[ ]+R_LARCH_B16[ ]+\.L1
[ ]+30:[ ]+5fffd085[ ]+bne[ ]+\$a0,[ ]+\$a1,[ ]+-48[ ]+#[ ]+0[ ]+<\.L1>
@@ -29,8 +29,10 @@ Disassembly of section .text:
[ ]+24:[ ]+R_LARCH_B21[ ]+.L1
[ ]+28:[ ]+50000000[ ]+b[ ]+0[ ]+#[ ]+0x28
[ ]+28:[ ]+R_LARCH_B26[ ]+.L1
+[ ]+28:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+2c:[ ]+54000000[ ]+bl[ ]+0[ ]+#[ ]+0x2c
[ ]+2c:[ ]+R_LARCH_B26[ ]+.L1
+[ ]+2c:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+30:[ ]+14000004[ ]+lu12i.w[ ]+\$a0,[ ]+0
[ ]+30:[ ]+R_LARCH_ABS_HI20[ ]+.L1
[ ]+34:[ ]+038000a4[ ]+ori[ ]+\$a0,[ ]+\$a1,[ ]+0x0
@@ -111,8 +113,10 @@ Disassembly of section .text:
[ ]+c0:[ ]+R_LARCH_B21[ ]+.L1\+0x8
[ ]+c4:[ ]+50000000[ ]+b[ ]+0[ ]+#[ ]+0xc4
[ ]+c4:[ ]+R_LARCH_B26[ ]+.L1\+0x8
+[ ]+c4:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+c8:[ ]+54000000[ ]+bl[ ]+0[ ]+#[ ]+0xc8
[ ]+c8:[ ]+R_LARCH_B26[ ]+.L1\+0x8
+[ ]+c8:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+cc:[ ]+14000004[ ]+lu12i.w[ ]+\$a0,[ ]+0
[ ]+cc:[ ]+R_LARCH_ABS_HI20[ ]+.L1\+0x8
[ ]+d0:[ ]+038000a4[ ]+ori[ ]+\$a0,[ ]+\$a1,[ ]+0x0
@@ -14,6 +14,7 @@ Disassembly of section .text:
[ ]+4: R_LARCH_B21[ ]+.L1
[ ]+8:[ ]+50008400[ ]+b[ ]+132[ ]+# 8c <.L1>
[ ]+8: R_LARCH_B26[ ]+.L1
+[ ]+8: R_LARCH_RELAX[ ]+\*ABS\*
[ ]+c:[ ]+14000004[ ]+lu12i.w[ ]+\$a0, 0
[ ]+c: R_LARCH_ABS_HI20[ ]+.L1
[ ]+10:[ ]+038000a4[ ]+ori[ ]+\$a0, \$a1, 0x0
new file mode 100644
@@ -0,0 +1,30 @@
+#...
+Disassembly of section .plt:
+#...
+00000001200004d0 <fn3@plt>:
+ 1200004d0: 1c00010f pcaddu12i \$t3, 8
+ 1200004d4: 28ed01ef ld.d \$t3, \$t3, -1216
+ 1200004d8: 4c0001ed jirl \$t1, \$t3, 0
+ 1200004dc: 03400000 nop
+
+Disassembly of section .text:
+#...
+0000000120000668 <main>:
+ 120000668: 03400000 nop
+ 12000066c: 03400000 nop
+ 120000670: 57fe63ff bl -416 # 1200004d0 <fn3@plt>
+
+0000000120000674 <medium_call_nop>:
+ 120000674: 03400000 nop
+ 120000678: 03400000 nop
+ 12000067c: 03400000 nop
+ 120000680: 03400000 nop
+ 120000684: 1e000001 pcaddu18i \$ra, 0
+ 120000688: 4ffe4c21 jirl \$ra, \$ra, -436
+
+000000012000068c <normal_call_delete>:
+ 12000068c: 57fe47ff bl -444 # 1200004d0 <fn3@plt>
+
+0000000120000690 <medium_call_delete>:
+ 120000690: 57fe43ff bl -448 # 1200004d0 <fn3@plt>
+#pass
new file mode 100644
@@ -0,0 +1,48 @@
+ .text
+ .align 2
+ .globl main
+ .type main, @function
+main:
+ # undefweak symbol with .hidden and .protected
+ # do not need plt entry, Calls to these symbols
+ # are converted to nop when relax is disabled.
+nornal_call_nop:
+ .option norelax
+ bl %plt(fn1)
+ bl %plt(fn2)
+ bl %plt(fn3)
+
+ # Medium call uses pcaddu18i+jirl, we need to
+ # convert two instructions to nop.
+medium_call_nop:
+ pcaddu18i $r1,%call36(fn1)
+ jirl $r1,$r1,0
+ pcaddu18i $r1,%call36(fn2)
+ jirl $r1,$r1,0
+ pcaddu18i $r1,%call36(fn3)
+ jirl $r1,$r1,0
+
+
+ # These insns call undefweak symbol without
+ # plt entry will be deleted when relax is
+ # enabled.
+normal_call_delete:
+ .option relax
+ bl %plt(fn1)
+ bl %plt(fn2)
+ bl %plt(fn3)
+medium_call_delete:
+ pcaddu18i $r1,%call36(fn1)
+ jirl $r1,$r1,0
+ pcaddu18i $r1,%call36(fn2)
+ jirl $r1,$r1,0
+ pcaddu18i $r1,%call36(fn3)
+ jirl $r1,$r1,0
+
+ .weak fn1
+ .hidden fn1
+
+ .weak fn2
+ .protected fn2
+
+ .weak fn3
@@ -25,8 +25,10 @@ Disassembly of section .text:
[ ]+20:[ ]+4c000080[ ]+jirl[ ]+\$zero,[ ]+\$a0,[ ]+0
[ ]+24:[ ]+53ffdfff[ ]+b[ ]+-36[ ]+#[ ]+0[ ]+<.L1>
[ ]+24:[ ]+R_LARCH_B26[ ]+.L1
+[ ]+24:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+28:[ ]+57ffdbff[ ]+bl[ ]+-40[ ]+#[ ]+0[ ]+<.L1>
[ ]+28:[ ]+R_LARCH_B26[ ]+.L1
+[ ]+28:[ ]+R_LARCH_RELAX[ ]+\*ABS\*
[ ]+2c:[ ]+5bffd485[ ]+beq[ ]+\$a0,[ ]+\$a1,[ ]+-44[ ]+#[ ]+0[ ]+<.L1>
[ ]+2c:[ ]+R_LARCH_B16[ ]+.L1
[ ]+30:[ ]+5fffd085[ ]+bne[ ]+\$a0,[ ]+\$a1,[ ]+-48[ ]+#[ ]+0[ ]+<.L1>
@@ -142,6 +142,16 @@ if [istarget "loongarch64-*-*"] {
"abs-global.out" \
] \
]
+
+ run_cc_link_tests [list \
+ [list \
+ "call undefweak symbol" \
+ "" "" \
+ {call_undefweak.s} \
+ {{objdump {-d} call_undefweak.d}} \
+ "call_undefweak" \
+ ] \
+ ]
}
if [istarget "loongarch64-*-*"] {