PERFORCE change 116023 for review
Oleksandr Tymoshenko
gonzo at FreeBSD.org
Sat Mar 17 12:42:24 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=116023
Change 116023 by gonzo at gonzo_jeeves on 2007/03/17 12:42:06
o Put together rtld magic both low-level and high-level.
Obtained from: NetBSD
Affected files ...
.. //depot/projects/mips2/src/libexec/rtld-elf/mips/reloc.c#2 edit
.. //depot/projects/mips2/src/libexec/rtld-elf/mips/rtld_start.S#2 edit
Differences ...
==== //depot/projects/mips2/src/libexec/rtld-elf/mips/reloc.c#2 (text+ko) ====
@@ -17,56 +17,15 @@
init_pltgot(Obj_Entry *obj)
{
if (obj->pltgot != NULL) {
- obj->pltgot[1] = (Elf_Addr) obj;
- obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
+ obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
+ obj->pltgot[1] |= (Elf_Addr) obj;
}
}
int
do_copy_relocations(Obj_Entry *dstobj)
{
- assert(NULL);
-#if 0
- const Elf_Rel *rellim;
- const Elf_Rel *rel;
-
- assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
-
- rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
- for (rel = dstobj->rel; rel < rellim; rel++) {
- if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
- void *dstaddr;
- const Elf_Sym *dstsym;
- const char *name;
- unsigned long hash;
- size_t size;
- const void *srcaddr;
- const Elf_Sym *srcsym;
- Obj_Entry *srcobj;
- const Ver_Entry *ve;
-
- dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
- dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
- name = dstobj->strtab + dstsym->st_name;
- hash = elf_hash(name);
- size = dstsym->st_size;
- ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
-
- for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
- if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
- break;
-
- if (srcobj == NULL) {
- _rtld_error("Undefined symbol \"%s\" referenced from COPY"
- " relocation in %s", name, dstobj->path);
- return -1;
- }
-
- srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
- memcpy(dstaddr, srcaddr, size);
- }
- }
-#endif
+ /* Do nothing */
return 0;
}
@@ -75,13 +34,34 @@
int open();
int _open();
+
+static __inline Elf_Addr
+load_ptr(void *where)
+{
+ Elf_Addr res;
+
+ memcpy(&res, where, sizeof(res));
+
+ return (res);
+}
+
+void
+store_ptr(void *where, Elf_Addr val)
+{
+
+ memcpy(where, &val, sizeof(val));
+}
+
void
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
{
const Elf_Rel *rel = 0, *rellim;
Elf_Addr relsz = 0;
+ const Elf_Sym *symtab = NULL, *sym;
Elf_Addr *where;
- uint32_t size;
+ Elf_Addr *got = NULL;
+ Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
+ int i;
for (; dynp->d_tag != DT_NULL; dynp++) {
switch (dynp->d_tag) {
@@ -91,16 +71,87 @@
case DT_RELSZ:
relsz = dynp->d_un.d_val;
break;
+ case DT_SYMTAB:
+ symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
+ break;
+ case DT_PLTGOT:
+ got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
+ break;
+ case DT_MIPS_LOCAL_GOTNO:
+ local_gotno = dynp->d_un.d_val;
+ break;
+ case DT_MIPS_SYMTABNO:
+ symtabno = dynp->d_un.d_val;
+ break;
+ case DT_MIPS_GOTSYM:
+ gotsym = dynp->d_un.d_val;
+ break;
}
}
+
+ i = (got[1] & 0x80000000) ? 2 : 1;
+ /* Relocate the local GOT entries */
+ got += i;
+
+ for (; i < local_gotno; i++)
+ *got++ += relocbase;
+
+ sym = symtab + gotsym;
+
+ /* Now do the global GOT entries */
+ for (i = gotsym; i < symtabno; i++) {
+ *got = sym->st_value + relocbase;
+ ++sym;
+ ++got;
+ }
+
rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
- size = (rellim - 1)->r_offset - rel->r_offset;
for (; rel < rellim; rel++) {
- where = (Elf_Addr *)(relocbase + rel->r_offset);
-
- *where += (Elf_Addr)relocbase;
+ where = (void *)(relocbase + rel->r_offset);
+
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_TYPE(NONE):
+ break;
+
+ case R_TYPE(REL32):
+ assert(ELF_R_SYM(rel->r_info) < gotsym);
+ sym = symtab + ELF_R_SYM(rel->r_info);
+ assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
+ if(load_ptr(where) + relocbase == 0x6008ed78) {
+ assert(where);
+ }
+ store_ptr(where, load_ptr(where) + relocbase);
+ break;
+
+ default:
+ abort();
+ break;
+ }
}
}
+
+Elf_Addr
+_mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
+{
+ Elf_Addr *got = obj->pltgot;
+ const Elf_Sym *def;
+ const Obj_Entry *defobj;
+ Elf_Addr target;
+
+ def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
+ if (def == NULL)
+ _rtld_error("bind failed no symbol");
+
+ target = (Elf_Addr)(defobj->relocbase + def->st_value);
+ dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
+ obj->path,
+ reloff, defobj->strtab + def->st_name,
+ (void *)got[obj->local_gotno + reloff - obj->gotsym],
+ (void *)target);
+ got[obj->local_gotno + reloff - obj->gotsym] = target;
+ return (Elf_Addr)target;
+}
+
/*
* It is possible for the compiler to emit relocations for unaligned data.
* We handle this situation with these inlines.
@@ -108,122 +159,92 @@
#define RELOC_ALIGNED_P(x) \
(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
-static __inline Elf_Addr
-load_ptr(void *where)
+/*
+ * Process non-PLT relocations
+ */
+int
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
{
- Elf_Addr res;
+ const Elf_Rel *rel;
+ const Elf_Rel *rellim;
+ Elf_Addr *got = obj->pltgot;
+ const Elf_Sym *sym, *def;
+ const Obj_Entry *defobj;
+ int i;
- memcpy(&res, where, sizeof(res));
+ /* The relocation for the dynamic loader has already been done. */
+ if (obj == obj_rtld)
+ return (0);
- return (res);
-}
+ i = (got[1] & 0x80000000) ? 2 : 1;
-static __inline void
-store_ptr(void *where, Elf_Addr val)
-{
+ /* Relocate the local GOT entries */
+ got += i;
+ for (; i < obj->local_gotno; i++)
+ *got++ += (Elf_Addr)obj->relocbase;
+ sym = obj->symtab + obj->gotsym;
- memcpy(where, &val, sizeof(val));
-}
+ /* Now do the global GOT entries */
+ for (i = obj->gotsym; i < obj->symtabno; i++) {
+ dbg(" doing got %d sym %p (%s, %x)", i - obj->gotsym, sym,
+ sym->st_name + obj->strtab, *got);
-static int
-reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
-{
- assert(NULL);
-#if 0
- Elf_Addr *where;
- const Elf_Sym *def;
- const Obj_Entry *defobj;
- Elf_Addr tmp;
- unsigned long symnum;
+ if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
+ sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
+ /*
+ * If there are non-PLT references to the function,
+ * st_value should be 0, forcing us to resolve the
+ * address immediately.
+ *
+ * XXX DANGER WILL ROBINSON!
+ * The linker is not outputting PLT slots for calls to
+ * functions that are defined in the same shared
+ * library. This is a bug, because it can screw up
+ * link ordering rules if the symbol is defined in
+ * more than one module. For now, if there is a
+ * definition, we fail the test above and force a full
+ * symbol lookup. This means that all intra-module
+ * calls are bound immediately. - mycroft, 2003/09/24
+ */
+ *got = sym->st_value + (Elf_Addr)obj->relocbase;
+ } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
+ /* Symbols with index SHN_ABS are not relocated. */
+ if (sym->st_shndx != SHN_ABS)
+ *got = sym->st_value +
+ (Elf_Addr)obj->relocbase;
+ } else {
+ /* TODO: add cache here */
+ def = find_symdef(i, obj, &defobj, false, NULL);
+ if (def == NULL)
+ return -1;
+ *got = def->st_value + (Elf_Addr)defobj->relocbase;
+ }
- where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
- symnum = ELF_R_SYM(rel->r_info);
+ dbg(" --> now %x", *got);
+ ++sym;
+ ++got;
+ }
- assert(NULL);
- switch (ELF_R_TYPE(rel->r_info)) {
- case R_MIPS_NONE:
- break;
-
- case R_ARM_PC24: { /* word32 S - P + A */
- Elf32_Sword addend;
-
- /*
- * Extract addend and sign-extend if needed.
- */
- addend = *where;
- if (addend & 0x00800000)
- addend |= 0xff000000;
-
- def = find_symdef(symnum, obj, &defobj, false, cache);
- if (def == NULL)
- return -1;
- tmp = (Elf_Addr)obj->relocbase + def->st_value
- - (Elf_Addr)where + (addend << 2);
- if ((tmp & 0xfe000000) != 0xfe000000 &&
- (tmp & 0xfe000000) != 0) {
- _rtld_error(
- "%s: R_ARM_PC24 relocation @ %p to %s failed "
- "(displacement %ld (%#lx) out of range)",
- obj->path, where,
- obj->strtab + obj->symtab[symnum].st_name,
- (long) tmp, (long) tmp);
- return -1;
- }
- tmp >>= 2;
- *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
- dbg("PC24 %s in %s --> %p @ %p in %s",
- obj->strtab + obj->symtab[symnum].st_name,
- obj->path, (void *)*where, where, defobj->path);
- break;
- }
+ got = obj->pltgot;
+ rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
+ for (rel = obj->rel; rel < rellim; rel++) {
+ void *where;
+ Elf_Addr tmp;
+ unsigned long symnum;
- case R_ARM_ABS32: /* word32 B + S + A */
- case R_ARM_GLOB_DAT: /* word32 B + S */
- def = find_symdef(symnum, obj, &defobj, false, cache);
- if (def == NULL)
- return -1;
- if (__predict_true(RELOC_ALIGNED_P(where))) {
- tmp = *where + (Elf_Addr)defobj->relocbase +
- def->st_value;
- *where = tmp;
- } else {
- tmp = load_ptr(where) +
- (Elf_Addr)defobj->relocbase +
- def->st_value;
- store_ptr(where, tmp);
- }
- dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
- obj->strtab + obj->symtab[symnum].st_name,
- obj->path, (void *)tmp, where, defobj->path);
- break;
+ where = obj->relocbase + rel->r_offset;
+ symnum = ELF_R_SYM(rel->r_info);
- case R_ARM_RELATIVE: /* word32 B + A */
- if (__predict_true(RELOC_ALIGNED_P(where))) {
- tmp = *where + (Elf_Addr)obj->relocbase;
- *where = tmp;
- } else {
- tmp = load_ptr(where) +
- (Elf_Addr)obj->relocbase;
- store_ptr(where, tmp);
- }
- dbg("RELATIVE in %s --> %p", obj->path,
- (void *)tmp);
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_TYPE(NONE):
break;
- case R_ARM_COPY:
- /*
- * These are deferred until all other relocations have
- * been done. All we do here is make sure that the
- * COPY relocation is not in a shared library. They
- * are allowed only in executable files.
- */
- if (!obj->mainprog) {
- _rtld_error(
- "%s: Unexpected R_COPY relocation in shared library",
- obj->path);
- return -1;
- }
- dbg("COPY (avoid in main)");
+ case R_TYPE(REL32):
+ /* 32-bit PC-relative reference */
+ def = obj->symtab + symnum;
+ tmp = load_ptr(where);
+ tmp += (Elf_Addr)obj->relocbase;
+ store_ptr(where, tmp);
break;
default:
@@ -236,52 +257,16 @@
"in non-PLT relocations\n",
obj->path, (u_long) ELF_R_TYPE(rel->r_info));
return -1;
- default:
+ }
}
-#endif
+
return 0;
}
/*
- * * Process non-PLT relocations
- * */
+ * Process the PLT relocations.
+ */
int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
-{
- const Elf_Rel *rellim;
- const Elf_Rel *rel;
- SymCache *cache;
- int bytes = obj->nchains * sizeof(SymCache);
- int r = -1;
-
- /* The relocation for the dynamic loader has already been done. */
- if (obj == obj_rtld)
- return (0);
- /*
- * The dynamic loader may be called from a thread, we have
- * limited amounts of stack available so we cannot use alloca().
- */
- cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
- if (cache == MAP_FAILED)
- cache = NULL;
-
- rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
- for (rel = obj->rel; rel < rellim; rel++) {
- if (reloc_nonplt_object(obj, rel, cache) < 0)
- goto done;
- }
- r = 0;
-done:
- if (cache) {
- munmap(cache, bytes);
- }
- return (r);
-}
-
-/*
- * * Process the PLT relocations.
- * */
-int
reloc_plt(Obj_Entry *obj)
{
const Elf_Rel *rellim;
@@ -291,10 +276,6 @@
obj->pltrelsize);
for (rel = obj->pltrel; rel < rellim; rel++) {
Elf_Addr *where;
-
- assert(NULL);
- /* assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); */
-
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
*where += (Elf_Addr )obj->relocbase;
}
@@ -303,39 +284,13 @@
}
/*
- * * LD_BIND_NOW was set - force relocation for all jump slots
- * */
+ * LD_BIND_NOW was set - force relocation for all jump slots
+ */
int
reloc_jmpslots(Obj_Entry *obj)
{
- assert(NULL);
-#if 0
- const Obj_Entry *defobj;
- const Elf_Rel *rellim;
- const Elf_Rel *rel;
- const Elf_Sym *def;
- Elf_Addr *where;
- Elf_Addr target;
-
- rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
- for (rel = obj->pltrel; rel < rellim; rel++) {
- assert(NULL);
- assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
- where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
- true, NULL);
- if (def == NULL) {
- dbg("reloc_jmpslots: sym not found");
- return (-1);
- }
-
- target = (Elf_Addr)(defobj->relocbase + def->st_value);
- reloc_jmpslot(where, target, defobj, obj,
- (const Elf_Rel *) rel);
- }
-
+ /* Do nothing */
obj->jmpslots_done = true;
-#endif
return (0);
}
@@ -345,14 +300,8 @@
const Obj_Entry *obj, const Elf_Rel *rel)
{
- assert(NULL);
-#if 0
- assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
-
- if (*where != target)
- *where = target;
+ /* Do nothing */
-#endif
return target;
}
==== //depot/projects/mips2/src/libexec/rtld-elf/mips/rtld_start.S#2 (text+ko) ====
@@ -34,6 +34,7 @@
.globl _C_LABEL(_rtld)
LEAF(rtld_start)
+ .abicalls
.set noreorder
.cpload t9
@@ -46,50 +47,66 @@
la a1, 1f
bal 1f
+ nop
+1: subu a1, ra, a1 # relocbase
la t9,_C_LABEL(_rtld_relocate_nonplt_self)
-1: subu a1, ra, a1 # relocbase
move s2,a1
la a0,_DYNAMIC
addu t9, a1, t9
jalr t9
- addu a0, a1, a0 # &_DYNAMIC
+ addu a0, a1, a0 # &_DYNAMIC
+
- move a1,s2 # relocbase
- addu a0, sp, 4 # sp
- jal _C_LABEL(_rtld) # v0 = _rtld(sp, relocbase)
- nop
+ addu a0, sp, 12 # sp
+ addu a1, sp, 4 # &exit_proc
+ addu a2, sp, 8 # &objp
+ addu sp, sp, -16 # arguments slot
+ jal _C_LABEL(_rtld) # v0 = _rtld(sp, exit_proc, objp)
+ nop
+ addu sp, sp, 16 #
- lw a1, 4(sp) # our atexit function
- lw a2, 8(sp) # obj_main entry
+ lw a0, 4(sp) # our atexit function
+ lw a1, 8(sp) # obj_main entry
addu sp, sp,12 # readjust stack
- move a0,s0 # stack pointer
move t9,v0
+ move a2,s1 # restore ps_strings
jr t9 # _start(sp, cleanup, obj);
- move a3,s1 # restore ps_strings
+ nop
END(rtld_start)
.globl _rtld_bind_start
.ent _rtld_bind_start
_rtld_bind_start:
+ # ABI conventions for stubs
+ # t8 contains symbol index
+ # t7 contains return address
+ .frame sp, 0, ra # satisfy compiler
move v1,gp # save old GP
add t9,8 # modify T9 to point at .cpload
.cpload t9
subu sp,44 # save arguments and sp value in stack
.cprestore 36
- sw a7,40(sp)
sw a0,16(sp)
sw a1,20(sp)
sw a2,24(sp)
sw a3,28(sp)
sw s0,32(sp)
+ sw t7,40(sp)
move s0,sp
- move a0,t8 # symbol index
- move a1,a7 # old RA
- move a2,v1 # old GP
- move a3,ra # current RA
- jal _C_LABEL(_rtld_bind)
+ move a0,v1 # old GP
+ subu a0,a0,0x7ff0 # The offset of $gp from the
+ # beginning of the .got section:
+ # $gp = .got + 0x7ff0, so
+ # .got = $gp - 0x7ff0
+ # Simple math as you can see.
+
+ lw a0,4(a0) # object = pltgot[1] & 0x7fffffff
+ and a0,a0,0x7fffffff
+ move a1,t8 # symbol index
+
+ jal _C_LABEL(_mips_rtld_bind)
nop
move sp,s0
lw ra,40(sp)
More information about the p4-projects
mailing list