86 lines
3 KiB
Diff
86 lines
3 KiB
Diff
Date: Sun, 30 Jun 2019 07:39:20 -0500
|
|
From: Samuel Holland <samuel@...lland.org>
|
|
To: musl@...ts.openwall.com
|
|
Cc: Samuel Holland <samuel@...lland.org>
|
|
Subject: [PATCH] add support for powerpc/powerpc64 unaligned relocations
|
|
|
|
R_PPC_UADDR32 (R_PPC64_UADDR64) has the same meaning as R_PPC_ADDR32
|
|
(R_PPC64_ADDR64), except that its address need not be aligned. For
|
|
powerpc64, BFD ld(1) will automatically convert between ADDR<->UADDR
|
|
relocations when the address is/isn't at its native alignment. This
|
|
will happen if, for example, there is a pointer in a packed struct.
|
|
|
|
gold and lld do not currently generate R_PPC64_UADDR64, but pass
|
|
through misaligned R_PPC64_ADDR64 relocations from object files,
|
|
possibly relaxing them to misaligned R_PPC64_RELATIVE. In both cases
|
|
(relaxed or not) this violates the PSABI, which defines the relevant
|
|
field type as "a 64-bit field occupying 8 bytes, the alignment of
|
|
which is 8 bytes unless otherwise specified."
|
|
|
|
All three linkers violate the PSABI on 32-bit powerpc, where the only
|
|
difference is that the field is 32 bits wide, aligned to 4 bytes.
|
|
|
|
Currently musl fails to load executables linked by BFD ld containing
|
|
R_PPC64_UADDR64, with the error "unsupported relocation type 43".
|
|
This change provides compatibility with BFD ld on powerpc64, and any
|
|
static linker on either architecture that starts following the PSABI
|
|
more closely.
|
|
---
|
|
arch/powerpc/reloc.h | 1 +
|
|
arch/powerpc64/reloc.h | 1 +
|
|
ldso/dynlink.c | 3 +++
|
|
src/internal/dynlink.h | 1 +
|
|
4 files changed, 6 insertions(+)
|
|
|
|
diff --git a/arch/powerpc/reloc.h b/arch/powerpc/reloc.h
|
|
index 1b4cab36..527b6b7c 100644
|
|
--- arch/powerpc/reloc.h
|
|
+++ arch/powerpc/reloc.h
|
|
@@ -9,6 +9,7 @@
|
|
#define TPOFF_K (-0x7000)
|
|
|
|
#define REL_SYMBOLIC R_PPC_ADDR32
|
|
+#define REL_USYMBOLIC R_PPC_UADDR32
|
|
#define REL_GOT R_PPC_GLOB_DAT
|
|
#define REL_PLT R_PPC_JMP_SLOT
|
|
#define REL_RELATIVE R_PPC_RELATIVE
|
|
diff --git a/arch/powerpc64/reloc.h b/arch/powerpc64/reloc.h
|
|
index faf70acd..5bdaeede 100644
|
|
--- arch/powerpc64/reloc.h
|
|
+++ arch/powerpc64/reloc.h
|
|
@@ -11,6 +11,7 @@
|
|
#define TPOFF_K (-0x7000)
|
|
|
|
#define REL_SYMBOLIC R_PPC64_ADDR64
|
|
+#define REL_USYMBOLIC R_PPC64_UADDR64
|
|
#define REL_GOT R_PPC64_GLOB_DAT
|
|
#define REL_PLT R_PPC64_JMP_SLOT
|
|
#define REL_RELATIVE R_PPC64_RELATIVE
|
|
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
|
|
index db543c19..b5ef4bfc 100644
|
|
--- ldso/dynlink.c
|
|
+++ ldso/dynlink.c
|
|
@@ -407,6 +407,9 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
|
|
case REL_PLT:
|
|
*reloc_addr = sym_val + addend;
|
|
break;
|
|
+ case REL_USYMBOLIC:
|
|
+ memcpy(reloc_addr, &(size_t){sym_val + addend}, sizeof(size_t));
|
|
+ break;
|
|
case REL_RELATIVE:
|
|
*reloc_addr = (size_t)base + addend;
|
|
break;
|
|
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
|
|
index 165bbedb..ffd06b04 100644
|
|
--- src/internal/dynlink.h
|
|
+++ src/internal/dynlink.h
|
|
@@ -28,6 +28,7 @@ typedef Elf64_Sym Sym;
|
|
enum {
|
|
REL_NONE = 0,
|
|
REL_SYMBOLIC = -100,
|
|
+ REL_USYMBOLIC,
|
|
REL_GOT,
|
|
REL_PLT,
|
|
REL_RELATIVE,
|
|
--
|
|
2.21.0
|