about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Holland <samuel@sholland.org>2019-06-30 07:39:20 -0500
committerRich Felker <dalias@aerifal.cx>2019-08-11 17:43:57 -0400
commit08869deb7efbda6e979886cb67e3d5843f92c2e8 (patch)
tree93547135ee0d59dd87831e8728f9c154e3d8e79e
parent71af5309874269bcc9e4b84ea716fab33d888c1d (diff)
downloadmusl-08869deb7efbda6e979886cb67e3d5843f92c2e8.tar.gz
musl-08869deb7efbda6e979886cb67e3d5843f92c2e8.tar.xz
musl-08869deb7efbda6e979886cb67e3d5843f92c2e8.zip
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.
-rw-r--r--arch/powerpc/reloc.h1
-rw-r--r--arch/powerpc64/reloc.h1
-rw-r--r--ldso/dynlink.c3
-rw-r--r--src/internal/dynlink.h1
4 files changed, 6 insertions, 0 deletions
diff --git a/arch/powerpc/reloc.h b/arch/powerpc/reloc.h
index 1b4cab36..527b6b7c 100644
--- a/arch/powerpc/reloc.h
+++ b/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
--- a/arch/powerpc64/reloc.h
+++ b/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 531811cc..edd91acd 100644
--- a/ldso/dynlink.c
+++ b/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
--- a/src/internal/dynlink.h
+++ b/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,