summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authormartin <martin@NetBSD.org>2019-12-09 16:14:10 +0000
committermartin <martin@NetBSD.org>2019-12-09 16:14:10 +0000
commite5628491ec591c8a805cbb4a36f81102be09554a (patch)
tree11a88191cfe6d26a9ba0d8ec82d5ebce4e145f81 /libexec
parent3d17a8c56a756d5dd5624ca34299107c9bbb7e54 (diff)
Pull up following revision(s) (requested by uwe in ticket #535):
libexec/ld.elf_so/arch/powerpc/ppc_reloc.c: revision 1.60 libexec/ld.elf_so/arch/powerpc/ppc_reloc.c: revision 1.59 Resolve ADDR16_LO, ADDR16_HI, and ADDR16_HA relocs. Recent GNU ld does not resolve them statically if the reloc is in a writable section and the symbol is not already referenced from text. Use existing lo() and hi() macros. Same object code is generated.
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ld.elf_so/arch/powerpc/ppc_reloc.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c b/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
index 83974c6e1da..b3fb4c1bf4c 100644
--- a/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
+++ b/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ppc_reloc.c,v 1.58 2018/12/30 03:23:46 christos Exp $ */
+/* $NetBSD: ppc_reloc.c,v 1.58.2.1 2019/12/09 16:14:10 martin Exp $ */
/*-
* Copyright (C) 1998 Tsubai Masanari
@@ -30,7 +30,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: ppc_reloc.c,v 1.58 2018/12/30 03:23:46 christos Exp $");
+__RCSID("$NetBSD: ppc_reloc.c,v 1.58.2.1 2019/12/09 16:14:10 martin Exp $");
#endif /* not lint */
#include <stdarg.h>
@@ -197,6 +197,9 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
case R_TYPE(ADDR32): /* <address> S + A */
#endif
case R_TYPE(GLOB_DAT): /* <address> S + A */
+ case R_TYPE(ADDR16_LO):
+ case R_TYPE(ADDR16_HI):
+ case R_TYPE(ADDR16_HA):
case R_TYPE(DTPMOD):
case R_TYPE(DTPREL):
case R_TYPE(TPREL):
@@ -234,6 +237,50 @@ _rtld_relocate_nonplt_objects(Obj_Entry *obj)
obj->path, (void *)*where, defobj->path));
break;
+ /*
+ * Recent GNU ld does not resolve ADDR16_{LO,HI,HA} if
+ * the reloc is in a writable section and the symbol
+ * is not already referenced from text.
+ */
+ case R_TYPE(ADDR16_LO): {
+ tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
+ rela->r_addend);
+
+ uint16_t tmp16 = lo(tmp);
+
+ uint16_t *where16 = (uint16_t *)where;
+ if (*where16 != tmp16)
+ *where16 = tmp16;
+ rdbg(("ADDR16_LO %s in %s --> #lo(%p) = 0x%x in %s",
+ obj->strtab + obj->symtab[symnum].st_name,
+ obj->path, (void *)tmp, tmp16, defobj->path));
+ break;
+ }
+
+ case R_TYPE(ADDR16_HI):
+ case R_TYPE(ADDR16_HA): {
+ tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
+ rela->r_addend);
+
+ uint16_t tmp16 = hi(tmp);
+ if (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HA)
+ && (tmp & __ha16))
+ ++tmp16; /* adjust to ha(tmp) */
+
+ uint16_t *where16 = (uint16_t *)where;
+ if (*where16 != tmp16)
+ *where16 = tmp16;
+ rdbg(("ADDR16_H%c %s in %s --> #h%c(%p) = 0x%x in %s",
+ (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI)
+ ? 'I' : 'A'),
+ obj->strtab + obj->symtab[symnum].st_name,
+ obj->path,
+ (ELF_R_TYPE(rela->r_info) == R_TYPE(ADDR16_HI)
+ ? 'i' : 'a'),
+ (void *)tmp, tmp16, defobj->path));
+ break;
+ }
+
case R_TYPE(RELATIVE): /* <address> B + A */
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
rdbg(("RELATIVE in %s --> %p", obj->path,