Index: head/libexec/rtld-elf/mips/reloc.c =================================================================== --- head/libexec/rtld-elf/mips/reloc.c +++ head/libexec/rtld-elf/mips/reloc.c @@ -67,21 +67,98 @@ #define GOT1_RESERVED_FOR_RTLD(got) ((got)[1] & GOT1_MASK) #endif +#ifdef __mips_n64 +/* + * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain + * the symbol index. The top 32-bits contain three relocation types encoded + * in big-endian integer with first relocation in LSB. This means for little + * endian we have to byte swap that integer (r_type). + */ +#define Elf_Sxword Elf64_Sxword +#define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64)) +#if BYTE_ORDER == LITTLE_ENDIAN +#undef ELF_R_SYM +#undef ELF_R_TYPE +#define ELF_R_SYM(r_info) ((r_info) & 0xffffffff) +#define ELF_R_TYPE(r_info) bswap32((r_info) >> 32) +#endif +#else +#define ELF_R_NXTTYPE_64_P(r_type) (0) +#define Elf_Sxword Elf32_Sword +#endif + +void _rtld_pltbind_start(void); + void init_pltgot(Obj_Entry *obj) { + if (obj->pltgot != NULL) { obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; if (GOT1_RESERVED_FOR_RTLD(obj->pltgot)) obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK; } + if (obj->mips_pltgot != NULL) { + obj->mips_pltgot[0] = (Elf_Addr) &_rtld_pltbind_start; + obj->mips_pltgot[1] = (Elf_Addr) obj; + } } int do_copy_relocations(Obj_Entry *dstobj) { - /* Do nothing */ - return 0; + const Obj_Entry *srcobj, *defobj; + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Sym *srcsym; + const Elf_Sym *dstsym; + const void *srcaddr; + const char *name; + void *dstaddr; + SymLook req; + size_t size; + int res; + + /* + * COPY relocs are invalid outside of the main program + */ + assert(dstobj->mainprog); + + 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_MIPS_COPY) + continue; + + dstaddr = (void *)(dstobj->relocbase + rel->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + if (srcobj == NULL) { + _rtld_error( +"Undefined symbol \"%s\" referenced from COPY relocation in %s", + name, dstobj->path); + return (-1); + } + + srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + + return (0); } void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); @@ -90,26 +167,6 @@ * It is possible for the compiler to emit relocations for unaligned data. * We handle this situation with these inlines. */ -#ifdef __mips_n64 -/* - * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain - * the symbol index. The top 32-bits contain three relocation types encoded - * in big-endian integer with first relocation in LSB. This means for little - * endian we have to byte swap that integer (r_type). - */ -#define Elf_Sxword Elf64_Sxword -#define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64)) -#if BYTE_ORDER == LITTLE_ENDIAN -#undef ELF_R_SYM -#undef ELF_R_TYPE -#define ELF_R_SYM(r_info) ((r_info) & 0xffffffff) -#define ELF_R_TYPE(r_info) bswap32((r_info) >> 32) -#endif -#else -#define ELF_R_NXTTYPE_64_P(r_type) (0) -#define Elf_Sxword Elf32_Sword -#endif - static __inline Elf_Sxword load_ptr(void *where, size_t len) { @@ -475,6 +532,20 @@ break; } + case R_TYPE(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_MIPS_COPY " + "relocation in shared library", obj->path); + return (-1); + } + break; + #ifdef __mips_n64 case R_TYPE(TLS_DTPMOD64): #else @@ -581,23 +652,25 @@ int reloc_plt(Obj_Entry *obj) { -#if 0 const Elf_Rel *rellim; const Elf_Rel *rel; - - dbg("reloc_plt obj:%p pltrel:%p sz:%s", obj, obj->pltrel, (int)obj->pltrelsize); - dbg("gottable %p num syms:%s", obj->pltgot, obj->symtabno ); - dbg("*****************************************************"); - rellim = (const Elf_Rel *)((char *)obj->pltrel + - obj->pltrelsize); - for (rel = obj->pltrel; rel < rellim; rel++) { + + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { Elf_Addr *where; - where = (Elf_Addr *)(obj->relocbase + rel->r_offset); - *where += (Elf_Addr )obj->relocbase; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_MIPS_JUMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where += (Elf_Addr )obj->relocbase; + break; + default: + _rtld_error("Unknown relocation type %u in PLT", + (unsigned int)ELF_R_TYPE(rel->r_info)); + return (-1); + } } -#endif - /* PLT fixups were done above in the GOT relocation. */ return (0); } @@ -607,9 +680,34 @@ int reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) { - /* Do nothing */ - obj->jmpslots_done = true; - + const Obj_Entry *defobj; + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Sym *def; + + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_MIPS_JUMP_SLOT: + def = find_symdef(ELF_R_SYM(rel->r_info), obj, + &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where = (Elf_Addr)(defobj->relocbase + def->st_value); + break; + default: + _rtld_error("Unknown relocation type %u in PLT", + (unsigned int)ELF_R_TYPE(rel->r_info)); + return (-1); + } + } + return (0); } @@ -635,9 +733,11 @@ const Obj_Entry *obj, const Elf_Rel *rel) { - /* Do nothing */ + assert(ELF_R_TYPE(rel->r_info) == R_MIPS_JUMP_SLOT); - return target; + if (*where != target && !ld_bind_not) + *where = target; + return (target); } void Index: head/libexec/rtld-elf/mips/rtld_start.S =================================================================== --- head/libexec/rtld-elf/mips/rtld_start.S +++ head/libexec/rtld-elf/mips/rtld_start.S @@ -100,6 +100,9 @@ #define XCALLFRAME_A4 (0*SZREG) #endif +/* + * Trampoline for "old" PLT stubs which use .got entries. + */ .globl _rtld_bind_start .ent _rtld_bind_start _rtld_bind_start: @@ -188,3 +191,94 @@ nop .cfi_endproc END(_rtld_bind_start) + + +/* + * Trampoline for PLT stubs using .pltrel entries and .got.plt. + */ + .globl _rtld_pltbind_start + .ent _rtld_pltbind_start +_rtld_pltbind_start: + .frame sp, XCALLFRAME_SIZ, $15 + .cfi_startproc simple + .cfi_register ra, $15 +#if defined(__mips_o32) + move v1, gp /* save pointer to .got.plt */ +#else + move v1, t2 /* save pointer to .got.plt */ +#endif +#if defined(__mips_o32) || defined(__mips_o64) + PTR_ADDU t9, 8 /* modify T9 to point at .cpload */ +#endif + SETUP_GP + PTR_SUBU sp, XCALLFRAME_SIZ /* save arguments and sp value in stack */ + .cfi_def_cfa sp, XCALLFRAME_SIZ + SETUP_GP64(XCALLFRAME_GP, _rtld_pltbind_start) + SAVE_GP(XCALLFRAME_GP) +#if defined(__mips_n32) || defined(__mips_n64) + REG_S a4, XCALLFRAME_A4(sp) + .cfi_rel_offset a4, XCALLFRAME_A4 + REG_S a5, XCALLFRAME_A5(sp) + .cfi_rel_offset a5, XCALLFRAME_A5 + REG_S a6, XCALLFRAME_A6(sp) + .cfi_rel_offset a6, XCALLFRAME_A6 + REG_S a7, XCALLFRAME_A7(sp) + .cfi_rel_offset a7, XCALLFRAME_A7 +#endif + REG_S a0, XCALLFRAME_A0(sp) + .cfi_rel_offset a0, XCALLFRAME_A0 + REG_S a1, XCALLFRAME_A1(sp) + .cfi_rel_offset a1, XCALLFRAME_A1 + REG_S a2, XCALLFRAME_A2(sp) + .cfi_rel_offset a2, XCALLFRAME_A2 + REG_S a3, XCALLFRAME_A3(sp) + .cfi_rel_offset a3, XCALLFRAME_A3 + REG_S $15, XCALLFRAME_RA(sp) /* ra is in t7/t3 */ + .cfi_rel_offset ra, XCALLFRAME_RA + REG_S s0, XCALLFRAME_S0(sp) + .cfi_rel_offset s0, XCALLFRAME_S0 + move s0, sp + + move a0, v1 /* .got.plt */ +#if defined(__mips_n64) + ld a0, 8(a0) /* object = .got.plt[1] */ + sll a1, t8, 4 /* PLT entry index to .rel.plt offset */ +#else + lw a0, 4(a0) /* object = .got.plt[1] */ + sll a1, t8, 3 /* PLT entry index to .rel.plt offset */ +#endif + + PTR_LA t9, _C_LABEL(_rtld_bind) + jalr t9 + nop + + move sp, s0 + REG_L ra, XCALLFRAME_RA(sp) + .cfi_restore ra + REG_L s0, XCALLFRAME_S0(sp) + .cfi_restore s0 + REG_L a0, XCALLFRAME_A0(sp) + .cfi_restore a0 + REG_L a1, XCALLFRAME_A1(sp) + .cfi_restore a1 + REG_L a2, XCALLFRAME_A2(sp) + .cfi_restore a2 + REG_L a3, XCALLFRAME_A3(sp) + .cfi_restore a3 +#if defined(__mips_n32) || defined(__mips_n64) + REG_L a4, XCALLFRAME_A4(sp) + .cfi_restore a4 + REG_L a5, XCALLFRAME_A5(sp) + .cfi_restore a5 + REG_L a6, XCALLFRAME_A6(sp) + .cfi_restore a6 + REG_L a7, XCALLFRAME_A7(sp) + .cfi_restore a7 +#endif + RESTORE_GP64 + PTR_ADDU sp, XCALLFRAME_SIZ + move t9, v0 + jr t9 + nop + .cfi_endproc +END(_rtld_pltbind_start) Index: head/libexec/rtld-elf/rtld.h =================================================================== --- head/libexec/rtld-elf/rtld.h +++ head/libexec/rtld-elf/rtld.h @@ -187,6 +187,7 @@ Elf_Word local_gotno; /* Number of local GOT entries */ Elf_Word symtabno; /* Number of dynamic symbols */ Elf_Word gotsym; /* First dynamic symbol in GOT */ + Elf_Addr *mips_pltgot; /* Second PLT GOT */ #endif #ifdef __powerpc64__ Elf_Addr glink; /* GLINK PLT call stub section */ Index: head/libexec/rtld-elf/rtld.c =================================================================== --- head/libexec/rtld-elf/rtld.c +++ head/libexec/rtld-elf/rtld.c @@ -1257,6 +1257,12 @@ case DT_MIPS_RLD_MAP: *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &r_debug; break; + + case DT_MIPS_PLTGOT: + obj->mips_pltgot = (Elf_Addr *) (obj->relocbase + + dynp->d_un.d_ptr); + break; + #endif #ifdef __powerpc64__ Index: head/sys/sys/elf_common.h =================================================================== --- head/sys/sys/elf_common.h +++ head/sys/sys/elf_common.h @@ -1059,6 +1059,8 @@ #define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ #define R_MIPS_JALR 37 #define R_MIPS_TLS_GD 42 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 #define R_PPC_NONE 0 /* No relocation. */ #define R_PPC_ADDR32 1