Date: Sat, 17 Mar 2007 12:42:23 GMT From: Oleksandr Tymoshenko <gonzo@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 116023 for review Message-ID: <200703171242.l2HCgNVc026664@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=116023 Change 116023 by gonzo@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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200703171242.l2HCgNVc026664>