aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorXi Ruoyao <xry111@xry111.site>2024-12-25 12:41:43 +0800
committercailulu <cailulu@loongson.cn>2024-12-27 17:52:29 +0800
commitbd94e7cd84c19da4a37dbdbc2d5587db6383f28c (patch)
treebd95e91fa2af12e704cf5a79194fd5a4a3c3d7b9 /bfd
parente65a355022d0dc6b5707310876a72b5693ec0aa5 (diff)
downloadbinutils-bd94e7cd84c19da4a37dbdbc2d5587db6383f28c.zip
binutils-bd94e7cd84c19da4a37dbdbc2d5587db6383f28c.tar.gz
binutils-bd94e7cd84c19da4a37dbdbc2d5587db6383f28c.tar.bz2
LoongArch: Fix resolution of undefined weak hidden/protected symbols
An undefined weak hidden/protect symbol should be resolved to runtime address 0, but we were actually resolving it to link-time address 0. So in PIE or DSO the runtime address would be incorrect. Fix the issue by rewriting pcalau12i to lu12i.w, and pcaddi to addi.w. The latter does not always work because the immediate field of addi.w is narrower, report an error in the case the addend is too large. Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elfnn-loongarch.c83
1 files changed, 61 insertions, 22 deletions
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 995d67c..4cf1512 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -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. */