diff options
-rw-r--r-- | lib/csu/powerpc64/crti.S | 37 | ||||
-rw-r--r-- | libexec/rtld-elf/powerpc64/reloc.c | 43 | ||||
-rw-r--r-- | libexec/rtld-elf/powerpc64/rtld_start.S | 26 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.c | 8 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.h | 3 | ||||
-rw-r--r-- | sys/powerpc/include/asm.h | 9 | ||||
-rw-r--r-- | sys/powerpc/powerpc/sigcode64.S | 1 |
7 files changed, 111 insertions, 16 deletions
diff --git a/lib/csu/powerpc64/crti.S b/lib/csu/powerpc64/crti.S index 767d920..00a1242 100644 --- a/lib/csu/powerpc64/crti.S +++ b/lib/csu/powerpc64/crti.S @@ -26,34 +26,59 @@ #include <machine/asm.h> __FBSDID("$FreeBSD$"); +#ifdef _CALL_ELF +.abiversion _CALL_ELF +#endif + .section .init,"ax",@progbits - .align 2 + .p2align 2 .globl _init +#if !defined(_CALL_ELF) || _CALL_ELF == 1 .section ".opd","aw" - .align 3 + .p2align 3 _init: .quad .L._init,.TOC.@tocbase,0 .previous .type _init,@function - .align 4 + .p2align 4 .L._init: +#else + .p2align 4 + .globl _init + .type _init,@function +_init: + addis %r2, %r12, (.TOC.-_init)@ha + addi %r2, %r2, (.TOC.-_init)@l + .localentry _init, .-_init +#endif stdu 1,-48(1) mflr 0 std 0,64(1) +/* Fini */ .section .fini,"ax",@progbits - .align 2 + .p2align 2 .globl _fini +#if !defined(_CALL_ELF) || _CALL_ELF == 1 .section ".opd","aw" - .align 3 + .p2align 3 _fini: .quad .L._fini,.TOC.@tocbase,0 .previous .type _fini,@function - .align 4 + .p2align 4 .L._fini: +#else + .p2align 4 + .globl _fini + .type _fini,@function +_fini: + addis %r2, %r12, (.TOC.-_fini)@ha + addi %r2, %r2, (.TOC.-_fini)@l + .localentry _fini, .-_fini +#endif stdu 1,-48(1) mflr 0 std 0,64(1) diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index ffa83fc..0c75a2a 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -43,11 +43,13 @@ #include "debug.h" #include "rtld.h" +#if !defined(_CALL_ELF) || _CALL_ELF == 1 struct funcdesc { Elf_Addr addr; Elf_Addr toc; Elf_Addr env; }; +#endif /* * Process the R_PPC_COPY relocations @@ -336,11 +338,14 @@ static int reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) { Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); +#if !defined(_CALL_ELF) || _CALL_ELF == 1 Elf_Addr *glink; +#endif long reloff; reloff = rela - obj->pltrela; +#if !defined(_CALL_ELF) || _CALL_ELF == 1 if (obj->priv == NULL) obj->priv = xmalloc(obj->pltrelasize); glink = obj->priv + reloff*sizeof(Elf_Addr)*2; @@ -351,6 +356,10 @@ reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) ((struct funcdesc *)(where))->env = (Elf_Addr)glink; *(glink++) = (Elf_Addr)obj; *(glink++) = reloff*sizeof(Elf_Rela); +#else + dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, reloff, obj->glink); + *where = (Elf_Addr)obj->glink + 4*reloff + 32; +#endif return (0); } @@ -416,7 +425,11 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) if (def == &sym_zero) { /* Zero undefined weak symbols */ +#if !defined(_CALL_ELF) || _CALL_ELF == 1 bzero(where, sizeof(struct funcdesc)); +#else + *where = 0; +#endif } else { reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *) rela); @@ -436,9 +449,6 @@ Elf_Addr reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, const Obj_Entry *obj, const Elf_Rel *rel) { - dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", - (void *)wherep, (void *)target, *(Elf_Addr *)target, - (Elf_Addr)defobj->relocbase); /* * At the PLT entry pointed at by `wherep', construct @@ -446,6 +456,11 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, * address. */ +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", + (void *)wherep, (void *)target, *(Elf_Addr *)target, + (Elf_Addr)defobj->relocbase); + memcpy(wherep, (void *)target, sizeof(struct funcdesc)); if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { /* @@ -459,8 +474,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, ((struct funcdesc *)(wherep))->toc += (Elf_Addr)defobj->relocbase; } +#else + dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, + (void *)target); + + *wherep = target; +#endif - __asm __volatile("dcbst 0,%0; sync" :: "r"(wherep) : "memory"); + __asm __volatile("sync" ::: "memory"); return (target); } @@ -485,6 +506,20 @@ reloc_gnu_ifunc(Obj_Entry *obj, int flags, void init_pltgot(Obj_Entry *obj) { +#if defined(_CALL_ELF) && _CALL_ELF == 2 + Elf_Addr *pltcall; + + pltcall = obj->pltgot; + + if (pltcall == NULL) { + return; + } + + pltcall[0] = (Elf_Addr)&_rtld_bind_start; + pltcall[1] = (Elf_Addr)obj; + + __asm __volatile("sync" ::: "memory"); +#endif } void diff --git a/libexec/rtld-elf/powerpc64/rtld_start.S b/libexec/rtld-elf/powerpc64/rtld_start.S index 186e16e..ee04d97 100644 --- a/libexec/rtld-elf/powerpc64/rtld_start.S +++ b/libexec/rtld-elf/powerpc64/rtld_start.S @@ -82,9 +82,13 @@ _ENTRY(_rtld_start) bl _rtld /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ nop +#if !defined(_CALL_ELF) || _CALL_ELF == 1 ld %r2,8(%r3) ld %r11,16(%r3) ld %r3,0(%r3) +#else + mr %r12,%r3 +#endif mtlr %r3 /* @@ -106,7 +110,11 @@ _ENTRY(_rtld_start) * _rtld_bind_start() * * Call into the MI binder. This routine is reached via the PLT call cell - * On entry, %r11 contains a pointer to the (object, relocation) tuple. + * + * For ELFv1, on entry, %r11 contains a pointer to the (object, relocation) + * tuple. + * + * For ELFv2, %r11 contains an object pointer and %r0 contains the PLT index. * * Save all registers, call into the binder to resolve and fixup the external * routine, and then transfer to the external routine on return. @@ -114,6 +122,7 @@ _ENTRY(_rtld_start) .globl _rtld_bind _ENTRY(_rtld_bind_start) + mr %r12,%r0 # shunt r0 immediately to r12 for ELFv2 mflr %r0 std %r0,16(%r1) # save lr mfcr %r0 @@ -121,7 +130,7 @@ _ENTRY(_rtld_bind_start) stdu %r1,-48-12*8(%r1) # stack space for 8 regs + header # + 2 save regs - std %r3,64+0*8(%r1) # save r3-r31 + std %r3,64+0*8(%r1) # save r3-r10 (arguments) std %r4,64+1*8(%r1) std %r5,64+2*8(%r1) std %r6,64+3*8(%r1) @@ -129,19 +138,27 @@ _ENTRY(_rtld_bind_start) std %r8,64+5*8(%r1) std %r9,64+6*8(%r1) std %r10,64+7*8(%r1) - std %r12,64+8*8(%r1) +#if !defined(_CALL_ELF) || _CALL_ELF == 1 ld %r3,0(%r11) ld %r4,8(%r11) +#else + mr %r3,%r11 + mulli %r4,%r12,24 /* Multiply index by sizeof(Elf_Rela) */ +#endif bl _rtld_bind # target addr = _rtld_bind(obj, reloff) nop +#if !defined(_CALL_ELF) || _CALL_ELF == 1 ld %r2,8(%r3) ld %r11,16(%r3) ld %r3,0(%r3) +#else + mr %r12,%r3 +#endif mtctr %r3 # move absolute target addr into ctr - ld %r3,64+0*8(%r1) # restore r3-r31 + ld %r3,64+0*8(%r1) # restore r3-r10 ld %r4,64+1*8(%r1) ld %r5,64+2*8(%r1) ld %r6,64+3*8(%r1) @@ -149,7 +166,6 @@ _ENTRY(_rtld_bind_start) ld %r8,64+5*8(%r1) ld %r9,64+6*8(%r1) ld %r10,64+7*8(%r1) - ld %r12,64+8*8(%r1) ld %r1,0(%r1) # restore stack ld %r0,8(%r1) # restore cr diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 7ba1e06..68ed46e 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1148,7 +1148,7 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, #ifdef __mips__ case DT_MIPS_LOCAL_GOTNO: obj->local_gotno = dynp->d_un.d_val; - break; + break; case DT_MIPS_SYMTABNO: obj->symtabno = dynp->d_un.d_val; @@ -1163,6 +1163,12 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, break; #endif +#ifdef __powerpc64__ + case DT_PPC64_GLINK: + obj->glink = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr); + break; +#endif + case DT_FLAGS_1: if (dynp->d_un.d_val & DF_1_NOOPEN) obj->z_noopen = true; diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index c7c5888..72a632e 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -187,6 +187,9 @@ typedef struct Struct_Obj_Entry { Elf_Word symtabno; /* Number of dynamic symbols */ Elf_Word gotsym; /* First dynamic symbol in GOT */ #endif +#ifdef __powerpc64__ + Elf_Addr glink; /* GLINK PLT call stub section */ +#endif const Elf_Verneed *verneed; /* Required versions. */ Elf_Word verneednum; /* Number of entries in verneed table */ diff --git a/sys/powerpc/include/asm.h b/sys/powerpc/include/asm.h index b3c979c..3aec5d3 100644 --- a/sys/powerpc/include/asm.h +++ b/sys/powerpc/include/asm.h @@ -61,17 +61,26 @@ #define HIDENAME(asmsym) __CONCAT(.,asmsym) #endif +#if !defined(_CALL_ELF) || _CALL_ELF == 1 #ifdef _KERNEL +/* ELFv1 kernel uses global dot symbols */ #define DOT_LABEL(name) __CONCAT(.,name) #define TYPE_ENTRY(name) .size name,24; \ .type DOT_LABEL(name),@function; \ .globl DOT_LABEL(name); #define END_SIZE(name) .size DOT_LABEL(name),.-DOT_LABEL(name); #else /* !_KERNEL */ +/* ELFv1 user code uses local function entry points */ #define DOT_LABEL(name) __CONCAT(.L.,name) #define TYPE_ENTRY(name) .type name,@function; #define END_SIZE(name) .size name,.-DOT_LABEL(name); #endif /* _KERNEL */ +#else +/* ELFv2 doesn't have any of this complication */ +#define DOT_LABEL(name) name +#define TYPE_ENTRY(name) .type name,@function; +#define END_SIZE(name) .size name,.-DOT_LABEL(name); +#endif #define _GLOBAL(name) \ .data; \ diff --git a/sys/powerpc/powerpc/sigcode64.S b/sys/powerpc/powerpc/sigcode64.S index 47be3ab..43d9ecb 100644 --- a/sys/powerpc/powerpc/sigcode64.S +++ b/sys/powerpc/powerpc/sigcode64.S @@ -57,6 +57,7 @@ CNAME(sigcode64): CNAME(sigcode64_elfv2): addi 1,1,-112 /* reserved space for callee */ + mflr 12 /* ELFv2 wants the address in r12 */ blrl addi 3,1,112+SF_UC /* restore sp, and get &frame->sf_uc */ |