@@ -3251,6 +3251,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
char tls_type;
bfd_vma relocation, off, ie_off, desc_off;
int i, j;
+ bool resolve_pcrel_undef_weak = false;
/* When an unrecognized relocation is encountered, which usually
occurs when using a newer assembler but an older linker, an error
@@ -4102,23 +4103,74 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
break;
+ case R_LARCH_PCALA64_HI12:
+ pc -= 4;
+ /* Fall through. */
+ case R_LARCH_PCALA64_LO20:
+ pc -= 8;
+ /* Fall through. */
case R_LARCH_PCREL20_S2:
- unresolved_reloc = false;
- if (h && h->plt.offset != MINUS_ONE)
- relocation = sec_addr (plt) + h->plt.offset;
- else
- relocation += rel->r_addend;
- relocation -= pc;
- break;
-
case R_LARCH_PCALA_HI20:
unresolved_reloc = false;
+
+ /* If sym is hidden undefined weak, (sym + addend) should be
+ resolved to runtime address (0 + addend). */
+ resolve_pcrel_undef_weak =
+ (is_undefweak
+ && h
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT);
+
+ if (resolve_pcrel_undef_weak)
+ pc = 0;
+
if (h && h->plt.offset != MINUS_ONE)
relocation = sec_addr (plt) + h->plt.offset;
else
relocation += rel->r_addend;
- RELOCATE_CALC_PC32_HI20 (relocation, pc);
+ switch (r_type)
+ {
+ case R_LARCH_PCREL20_S2:
+ relocation -= pc;
+ if (resolve_pcrel_undef_weak)
+ {
+ bfd_signed_vma addr = (bfd_signed_vma) relocation;
+ if (addr >= 2048 || addr < -2048)
+ {
+ const char *msg =
+ _("cannot resolve R_LARCH_PCREL20_S2 against "
+ "undefined weak symbol with addend out of "
+ "[-2048, 2048)");
+ fatal =
+ loongarch_reloc_is_fatal (info, input_bfd,
+ input_section, rel,
+ howto,
+ bfd_reloc_notsupported,
+ is_undefweak, name, msg);
+ break;
+ }
+
+ uint32_t insn = bfd_get (32, input_bfd,
+ contents + rel->r_offset);
+ insn = LARCH_GET_RD (insn) | LARCH_OP_ADDI_W;
+ insn |= (relocation & 0xfff) << 10;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_continue;
+ }
+ break;
+ case R_LARCH_PCALA_HI20:
+ RELOCATE_CALC_PC32_HI20 (relocation, pc);
+ if (resolve_pcrel_undef_weak)
+ {
+ uint32_t insn = bfd_get (32, input_bfd,
+ contents + rel->r_offset);
+ insn = LARCH_GET_RD (insn) | LARCH_OP_LU12I_W;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
+ break;
+ default:
+ RELOCATE_CALC_PC64_HI32 (relocation, pc);
+ }
break;
case R_LARCH_TLS_LE_HI20_R:
@@ -4155,19 +4207,6 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
break;
- case R_LARCH_PCALA64_HI12:
- pc -= 4;
- /* Fall through. */
- case R_LARCH_PCALA64_LO20:
- if (h && h->plt.offset != MINUS_ONE)
- relocation = sec_addr (plt) + h->plt.offset;
- else
- relocation += rel->r_addend;
-
- RELOCATE_CALC_PC64_HI32 (relocation, pc - 8);
-
- break;
-
case R_LARCH_GOT_PC_HI20:
case R_LARCH_GOT_HI20:
/* Calc got offset. */
@@ -36,6 +36,7 @@ extern "C"
#define LARCH_MK_ADDI_D 0xffc00000
#define LARCH_OP_ADDI_D 0x02c00000
+ #define LARCH_OP_ADDI_W 0x02800000
#define LARCH_MK_PCADDI 0xfe000000
#define LARCH_OP_PCADDI 0x18000000
#define LARCH_MK_B 0xfc000000
@@ -44,6 +45,7 @@ extern "C"
#define LARCH_OP_BL 0x54000000
#define LARCH_MK_ORI 0xffc00000
#define LARCH_OP_ORI 0x03800000
+ #define LARCH_OP_OR 0x00150000
#define LARCH_MK_LU12I_W 0xfe000000
#define LARCH_OP_LU12I_W 0x14000000
#define LARCH_MK_LD_D 0xffc00000
@@ -184,6 +184,7 @@ if [istarget "loongarch64-*-*"] {
run_dump_test "bad_pcala_hi20_weak_pie"
run_dump_test "bad_pcrel20_s2_global"
run_dump_test "bad_pcrel20_s2_weak"
+ run_dump_test "weak-undef-hidden-shared"
}
if [check_pie_support] {
@@ -194,6 +195,7 @@ if [istarget "loongarch64-*-*"] {
run_dump_test "relr-got-start"
run_dump_test "relr-text-pie"
run_dump_test "abssym_pie"
+ run_dump_test "weak-undef-hidden-pie"
}
run_dump_test "max_imm_b16"
new file mode 100644
@@ -0,0 +1,14 @@
+#source: weak-undef-hidden.s
+#ld: -pie -Ttext=0x1111222233334ff0
+#objdump: -d
+
+#...
+1111222233334ff0:[ ]+159999a4[ ]+lu12i.w[ ]+\$a0,[ ]+-209715
+1111222233334ff4:[ ]+02f77405[ ]+li.d[ ]+\$a1,[ ]+-547
+1111222233334ff8:[ ]+17777765[ ]+lu32i.d[ ]+\$a1,[ ]+-279621
+1111222233334ffc:[ ]+032aa8a5[ ]+lu52i.d[ ]+\$a1,[ ]+\$a1,[ ]+-1366
+1111222233335000:[ ]+00109484[ ]+add.d[ ]+\$a0,[ ]+\$a0,[ ]+\$a1
+1111222233335004:[ ]+029ffc06[ ]+li.w[ ]+\$a2,[ ]+2047
+1111222233335008:[ ]+02a00007[ ]+li.w[ ]+\$a3,[ ]+-2048
+111122223333500c:[ ]+4c000020[ ]+ret
+#pass
new file mode 100644
@@ -0,0 +1,14 @@
+#source: weak-undef-hidden.s
+#ld: -shared -Ttext=0x1111222233334ff0
+#objdump: -d
+
+#...
+1111222233334ff0:[ ]+159999a4[ ]+lu12i.w[ ]+\$a0,[ ]+-209715
+1111222233334ff4:[ ]+02f77405[ ]+li.d[ ]+\$a1,[ ]+-547
+1111222233334ff8:[ ]+17777765[ ]+lu32i.d[ ]+\$a1,[ ]+-279621
+1111222233334ffc:[ ]+032aa8a5[ ]+lu52i.d[ ]+\$a1,[ ]+\$a1,[ ]+-1366
+1111222233335000:[ ]+00109484[ ]+add.d[ ]+\$a0,[ ]+\$a0,[ ]+\$a1
+1111222233335004:[ ]+029ffc06[ ]+li.w[ ]+\$a2,[ ]+2047
+1111222233335008:[ ]+02a00007[ ]+li.w[ ]+\$a3,[ ]+-2048
+111122223333500c:[ ]+4c000020[ ]+ret
+#pass
new file mode 100644
@@ -0,0 +1,9 @@
+.weak undef
+.hidden undef
+
+.globl _start
+_start:
+ la.pcrel $a0, $a1, undef + 0xaaabbbbbcccccddd
+ pcaddi $a2, undef + 0x7ff
+ pcaddi $a3, undef - 0x800
+ ret