about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-08-05 12:50:26 -0400
committerRich Felker <dalias@aerifal.cx>2012-08-05 12:50:26 -0400
commitbabf820180368f00742ec65b2050a82380d7c542 (patch)
tree54cd3b26abca846f4f535abe3e90d293e4b3e9de /src
parentd04378016bfc993d8727215d79567a1c52904ade (diff)
downloadmusl-babf820180368f00742ec65b2050a82380d7c542.tar.gz
musl-babf820180368f00742ec65b2050a82380d7c542.tar.xz
musl-babf820180368f00742ec65b2050a82380d7c542.zip
mips dynamic linker support
not heavily tested, but the basics are working. the basic concept is
that the dynamic linker entry point code invokes a pure-PIC (no global
accesses) C function in reloc.h to perform the early GOT relocations
needed to make the dynamic linker itself functional, then invokes
__dynlink like on other archs. since mips uses some ugly arch-specific
hacks to optimize relocating the GOT (rather than just using the
normal DT_REL[A] tables like on other archs), the dynamic linker has
been modified slightly to support calling arch-specific relocation
code in reloc.h.

most of the actual mips-specific behavior was developed by reading the
output of readelf on libc.so and simple executable files. i could not
find good reference information on which relocation types need to be
supported or their semantics, so it's possible that some legitimate
usage cases will not work yet.
Diffstat (limited to 'src')
-rw-r--r--src/ldso/dynlink.c3
-rw-r--r--src/ldso/mips/start.s46
2 files changed, 49 insertions, 0 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 08f9118d..8f32f98f 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -487,6 +487,9 @@ static void reloc_all(struct dso *p)
 	for (; p; p=p->next) {
 		if (p->relocated) continue;
 		decode_vec(p->dynv, dyn, DYN_CNT);
+#ifdef NEED_ARCH_RELOCS
+		do_arch_relocs(p, head);
+#endif
 		do_relocs(p, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ],
 			2+(dyn[DT_PLTREL]==DT_RELA));
 		do_relocs(p, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], 2);
diff --git a/src/ldso/mips/start.s b/src/ldso/mips/start.s
new file mode 100644
index 00000000..d060dbc9
--- /dev/null
+++ b/src/ldso/mips/start.s
@@ -0,0 +1,46 @@
+.hidden _DYNAMIC
+.hidden __reloc_self
+.set noreorder
+.set nomacro
+.global _start
+.type _start,@function
+_start:
+	move $fp, $0
+
+	bgezal $0, 1f
+	nop
+2:	.gpword 2b
+	.gpword _DYNAMIC
+	.gpword __reloc_self
+1:	lw $gp, 0($ra)
+	subu $gp, $ra, $gp
+
+	lw $4, 0($sp)
+	addiu $5, $sp, 4
+	lw $6, 4($ra)
+	addu $6, $6, $gp
+	addiu $7, $gp, -0x7ff0
+	subu $sp, $sp, 16
+	lw $25, 8($ra)
+	add $25, $25, $gp
+	jalr $25
+	nop
+
+	lw $25, %call16(__dynlink)($gp)
+	lw $4, 16($sp)
+	addiu $5, $sp, 20
+	jalr $25
+	nop
+
+	add $sp, $sp, 16
+	li $6, -1
+1:	lw $4, ($sp)
+	lw $5, 4($sp)
+	bne $5, $6, 2f
+	nop
+	addu $sp, $sp, 4
+	addu $4, $4, -4
+	b 1b
+	nop
+2:	sw $4, ($sp)
+	jr $2