summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/csu/powerpc64/crti.S37
-rw-r--r--libexec/rtld-elf/powerpc64/reloc.c43
-rw-r--r--libexec/rtld-elf/powerpc64/rtld_start.S26
-rw-r--r--libexec/rtld-elf/rtld.c8
-rw-r--r--libexec/rtld-elf/rtld.h3
-rw-r--r--sys/powerpc/include/asm.h9
-rw-r--r--sys/powerpc/powerpc/sigcode64.S1
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 */
OpenPOWER on IntegriCloud