mirror of git://git.musl-libc.org/musl
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.
This commit is contained in:
parent
d04378016b
commit
babf820180
|
@ -4,7 +4,7 @@
|
|||
#define ETC_LDSO_PATH "/etc/ld-musl-mips.path"
|
||||
|
||||
#define IS_COPY(x) ((x)==R_MIPS_COPY)
|
||||
#define IS_PLT(x) ((x)==R_MIPS_JUMP_SLOT)
|
||||
#define IS_PLT(x) 1
|
||||
|
||||
static inline void do_single_reloc(size_t *reloc_addr, int type, size_t sym_val, size_t sym_size, unsigned char *base_addr, size_t addend)
|
||||
{
|
||||
|
@ -13,11 +13,61 @@ static inline void do_single_reloc(size_t *reloc_addr, int type, size_t sym_val,
|
|||
*reloc_addr = sym_val;
|
||||
break;
|
||||
case R_MIPS_REL32:
|
||||
// FIXME: how do symbolic relocs come in here ?
|
||||
*reloc_addr += (size_t)base_addr;
|
||||
if (sym_val) *reloc_addr += sym_val;
|
||||
else *reloc_addr += (size_t)base_addr;
|
||||
break;
|
||||
case R_MIPS_COPY:
|
||||
memcpy(reloc_addr, (void *)sym_val, sym_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __reloc_self(int c, size_t *a, size_t *dynv, size_t *got)
|
||||
{
|
||||
char *base;
|
||||
size_t t[20], n;
|
||||
for (a+=c+1; *a; a++);
|
||||
for (a++; *a; a+=2) if (*a<20) t[*a] = a[1];
|
||||
base = (char *)t[AT_BASE];
|
||||
if (!base) base = (char *)(t[AT_PHDR] & -4096);
|
||||
for (a=dynv; *a; a+=2) if (*a-0x70000000UL<20) t[*a&31] = a[1];
|
||||
n = t[DT_MIPS_LOCAL_GOTNO - 0x70000000];
|
||||
for (a=got; n; a++, n--) *a += (size_t)base;
|
||||
}
|
||||
|
||||
static void do_relocs(unsigned char *base, size_t *rel, size_t rel_size, size_t stride, Sym *syms, char *strings, struct dso *dso);
|
||||
|
||||
static void do_arch_relocs(struct dso *this, struct dso *head)
|
||||
{
|
||||
unsigned char *base = this->base;
|
||||
size_t *dynv = this->dynv;
|
||||
size_t dyn[20] = {0};
|
||||
size_t i;
|
||||
size_t rel[2], got=0;
|
||||
Sym *sym;
|
||||
|
||||
for (i=0; dynv[i]; i+=2) {
|
||||
if (dynv[i]-0x70000000UL<20)
|
||||
dyn[dynv[i]&31] = dynv[i+1];
|
||||
else if (dynv[i] == DT_PLTGOT)
|
||||
got = dynv[i+1];
|
||||
}
|
||||
i = dyn[DT_MIPS_LOCAL_GOTNO-0x70000000];
|
||||
if (this->shortname && !strcmp(this->shortname, "libc.so")) {
|
||||
got += sizeof(size_t) * i;
|
||||
} else {
|
||||
for (; i; i--, got+=sizeof(size_t))
|
||||
*(size_t *)(base+got) += (size_t)base;
|
||||
}
|
||||
sym = this->syms + dyn[DT_MIPS_GOTSYM-0x70000000];
|
||||
i = dyn[DT_MIPS_SYMTABNO-0x70000000] - dyn[DT_MIPS_GOTSYM-0x70000000];
|
||||
for (; i; i--, got+=sizeof(size_t), sym++) {
|
||||
rel[0] = got;
|
||||
rel[1] = sym-this->syms << 8 | R_MIPS_JUMP_SLOT;
|
||||
*(size_t *)(base+got) = 0;
|
||||
do_relocs(base, rel, sizeof rel, 2, this->syms, this->strings, head);
|
||||
}
|
||||
}
|
||||
|
||||
#define NEED_ARCH_RELOCS 1
|
||||
#define DYNAMIC_IS_RO 1
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue