Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ld.elf_so/arch/vax Simplify. If we got called via a...



details:   https://anonhg.NetBSD.org/src/rev/a7a2430a4cc9
branches:  trunk
changeset: 327930:a7a2430a4cc9
user:      matt <matt%NetBSD.org@localhost>
date:      Fri Mar 21 14:03:30 2014 +0000

description:
Simplify.  If we got called via a calls $n, *pcrel32, instead of constructing
a new stack frame, back up the PC by 7 and return back to the calls so it
will be reinvoked.  (This is by far the most common way it gets invoked).
Otherwise rebuild a new callframe and jump to the routine.

diffstat:

 libexec/ld.elf_so/arch/vax/rtld_start.S |  274 ++++++++++++++++++++++---------
 1 files changed, 195 insertions(+), 79 deletions(-)

diffs (truncated from 306 to 300 lines):

diff -r 9cee67147350 -r a7a2430a4cc9 libexec/ld.elf_so/arch/vax/rtld_start.S
--- a/libexec/ld.elf_so/arch/vax/rtld_start.S   Fri Mar 21 13:30:39 2014 +0000
+++ b/libexec/ld.elf_so/arch/vax/rtld_start.S   Fri Mar 21 14:03:30 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: rtld_start.S,v 1.20 2014/03/19 21:52:00 joerg Exp $    */
+/*     $NetBSD: rtld_start.S,v 1.21 2014/03/21 14:03:30 matt Exp $     */
 
 /*
  * Copyright 1996 Matt Thomas <matt%3am-software.com@localhost>
@@ -57,102 +57,218 @@
 
 /*
  * Lazy binding entry point, called via PLT via JMP into pltgot[1].
+ * SP+4: address to relocation offset
  * SP+0: obj entry points
- * SP+4: address to relocation index
- *
- * Note: Some functions rely on there not being an additional call frame;
- * hence the `optimization' to avoid the callg opportunistically.
  */
 ALTENTRY(_rtld_bind_start)
-       movab   -64(%sp),%sp    /* reserve some space */
-       pushr   $0x3f           /* save R0-R5 */
        movq    -8(%fp),%r0     /* get addresses of plt.got & reloc index */
-       pushl   (%r1)           /* push relocation index */
+       pushl   (%r1)           /* push relocation offset */
        pushl   %r0             /* push address of obj entry */
        calls   $2,_rtld_bind
 
-       addl3   $2,%r0,%r3              /* save routine address */
-       extzv   $0,$12,(%r0),%r1        /* get entry mask */
-       extzv   $0,$12,6(%fp),%r2       /* get saved mask */
-       cmpw    %r1,%r2         /* compare them */
-       bneq    12f             /* if they are different, rebuild */
-       movl    %r3,-4(%fp)     /* save routine address */
-       popr    $0x3f           /* pop registers */
-       movab   68(%sp),%sp     /* restore sp */
-       rsb                     /* and jump to it */
+       /*
+        * This code checks to see if we got called via a call{s,g} $n,*pcrel32
+        * This is by far the most common case (a call indirectly via the PLT).
+        */
+       subl3   $7,16(%fp),%r1  /* return address */
+       bicb3   $1,(%r1),%r2    /* fetch opcode of instruction */
+       cmpb    $0xfa,%r2       /* is it calls/callg */
+       jneq    20f             /*   no it isn't */
+       cmpb    $0xff,2(%r1)    /* and deferred 32-bit PC displacement? */
+       jneq    20f             /*   no it isn't */
+
+       /*
+        * This makes sure the longword with the PLT's address has been updated
+        * to point to the routine's address.  If it hasn't, then returning
+        * would put us in an infinite loop.  Instead we punt and fake up a
+        * callframe.
+        */
+       movl    3(%r1),%r3      /* get displacement */
+       addl2   16(%fp),%r3     /* add ending location */
+       cmpl    (%r3),%r0       /* does it contain the routine address? */
+#ifdef DEBUG
+       jneq    30f             /*   no it doesn't, die */
+#else
+       jneq    20f             /*   no it doesn't, go fake a new callframe */
+#endif
+
+11:    movl    %r1,16(%fp)     /* backup to the calls/callg */
+       jbc     $29,4(%fp),12f  /* skip if this was a callg */
+       clrl    (%ap)           /* clear argument count */
+12:    ret                     /* return and redo the call */
+
+#if 1
+20:
+       /*
+        * Since the calling standard says only r6-r11 should be saved,
+        * that simplies things for us.  That means we can use r0-r5 as
+        * temporaries without worrying about preserving them.  This means
+        * can hold the current fixed callframe in r2-r5 as we build the
+        * callframe without having to worry about overwriting the existing
+        * callframe.
+        */
+       extzv   $0,$12,(%r0),%r1/* get routine's save mask */
+       bitw    $0x3f,%r1       /* does the routine use r0-r5? */
+       jneq    30f             /*   yes, that sucks */
+       jbc     $29,4(%fp),27f  /* handle callg */
+       movq    4(%fp),%r2      /* fetch callframe status & saved AP */
+       movq    12(%fp),%r4     /* fetch callframe saved FP & PC */
+       insv    %r1,$16,$12,%r2 /* update save mask */
+       movl    %ap,%sp         /* reset stack to top of callframe */
+22:    pushr   %r1             /* push registers */
+       movq    %r4,-(%sp)      /* push callframe saved FP & PC */
+       movq    %r2,-(%sp)      /* push callframe status & saved AP */
+       pushl   $0              /* push condition handler */
+       movl    %sp,%fp         /* sp == fp now */
+#if 1
+       jmp     2(%r0)          /* jump past entry mask */
+#else
+       /*
+        * More correct but IV/DV are never set so ignore doing this for now.
+        */
+       movpsl  -(%sp)          /* push PSL */
+       clrb    (%sp)           /* clear user flags */
+       jbc     $14,(%r0),24f   /* IV need to be set? */
+       bisb2   $0x20,(%sp)     /*   yes, set it. */
+24:    jbc     $15,(%r0),25f   /* DV need to be set? */
+       bisb2   $0x80,(%sp)     /*   yes, set it. */
+25:    pushab  2(%r0)          /* push address of first instruction */
+       rei                     /* and go to it (updating PSW) */
+#endif
 
        /*
-        * We need to rebuild the callframe.  Save the current one in case
-        * we might overwrite it.
-        */
-12:    movq    4(%fp),-(%sp)   /* save PSW and AP */
-       movq    12(%fp),-(%sp)  /* save FP and return address */
-       /*
-        * Find out where this this call frame ends.
-        */
-       movl    %ap,%r0         /* get past callframe and registers */
-       bbs     $29,4(%fp),22f  /* calls is easy, it's where AP is */
-       /*
-        * Callg not so much
+        * Count how many registers are being used for callg.
         */
-       movab   20(%fp),%r0     /* past fixed callframe */
-       tstw    %r2             /* no saved registers? */
-       beql    22f             /*    none, so we are done. */
-       movl    $11,%r4         /* start with register 11 */
-20:    bbc     %r4,%r2,21f     /* save this register? */
-       addl2   $4,%r0          /*   yes, adjust for saved register */
-21:    sobgeq  %r4,20b         /* try next register */
+27:    movl    $0x32212110,%r3 /* bit counts */
+       extzv   $6,$3,%r1,%r2   /* extract bits 6-8 */
+       ashl    $2,%r2,%r2      /* shift by 2 */
+       extzv   %r2,$4,%r3,%r4  /* extract count */
+       extzv   $9,$3,%r1,%r2   /* extract bits 9-11 */
+       ashl    $2,%r2,%r2      /* shift by 2 */
+       extzv   %r2,$4,%r3,%r5  /* extract count */
+       movq    4(%fp),%r2      /* fetch callframe status & saved AP */
+       insv    %r1,$16,$12,%r2 /* update save mask */
+       addl3   %r3,r4,%r1      /* add counts and discard them */
+       movq    12(%fp),%r4     /* fetch callframe saved FP & PC */
+       moval   20(%fp)[%r1],%sp/* pop callframe */
+       extzv   $16,$12,%r2,%r1 /* get save mask back */
+       jbr     22b             /* now build the new callframe */
 
-22:
+30:    
+       calls   $0,_C_LABEL(_rtld_die)
+#else
        /*
-        * First "push" the caller saved registers (if there any that
-        * need to saved.)
+        * Check to see if called via call? $n,w^off(reg)
         */
-       tstw    %r1             /* if there are no registers to save */
-       beql    1f              /* just push the callframe */
-       cmpw    %r1,$63         /* if there are no caller-saved registers */
-       blequ   5f              /* skip them */
-       bbc     $11,%r1,10f     /* does it need to be saved? */
-       movl    %r11,-(%r0)
-10:    bbc     $10,%r1,9f      /* does it need to be saved? */
-       movl    %r10,-(%r0)
-9:     bbc     $9,%r1,8f       /* does it need to be saved? */
-       movl    %r9,-(%r0)
-8:     bbc     $8,%r1,7f       /* does it need to be saved? */
-       movl    %r8,-(%r0)
-7:     bbc     $7,%r1,6f       /* does it need to be saved? */
-       movl    %r7,-(%r0)
-6:     bbc     $6,%r1,5f       /* does it need to be saved? */
-       movl    %r6,-(%r0)
-5:     
+20:    addl2   $2,%r1          /* 16-bit displacement */
+       bicb3   $1,(%r1),%r2    /* fetch opcode of instruction */
+       cmpb    $0xfa,%r2       /* is it calls/callg */
+       jneq    30f             /*   no it isn't */
+       bicb3   $0x1f,2(%r1),%r3/* extract addressing mode */
+       cmpb    $0xc0,%r3       /* 16-bit displacement? */
+       jeql    11b             /*   yes, redo the call */
+       halt
+
        /*
-        * r0-r5 are not normally preserved so we should be done.
+        * Check to see if called via call? $n,b^off(reg)
         */
-       cmpw    %r1,$63
-       bgtru   1f
+30:    incl    %r1             /* 8-bit displacement */
+       bicb3   $1,(%r1),%r2    /* fetch opcode of instruction */
+       cmpb    $0xfa,%r2       /* is it calls/callg */
+       jneq    40f             /*   no it isn't */
+       bicb3   $0x1f,2(%r1),%r3/* extract addressing mode */
+       cmpb    $0xa0,%r3       /* 8-bit displacement? */
+       jeql    11b             /*   yes, redo the call */
+       halt
+
        /*
-        * For some reason, we have to preserve these.
+        * Check to see if called via call? $n,(reg)
         */
-       movab   16(%sp),%r2
-       bbc     $5,%r1,4f       /* does it need to be saved? */
-       movl    20(%r2),-(%r0)
-4:     bbc     $4,%r1,3f       /* does it need to be saved? */
-       movl    16(%r2),-(%r0)
-3:     bbc     $3,%r1,2f       /* does it need to be saved? */
-       movl    12(%r2),-(%r0)
-2:     bbc     $2,%r1,1f       /* does it need to be saved? */
-       movl    8(%r2),-(%r0)
+40:    incl    %r1             /* no displacement */
+       bicb3   $1,(%r1),%r2    /* fetch opcode of instruction */
+       cmpb    $0xfa,%r2       /* is it calls/callg */
+       jeql    41f             /*   yes it is */
+       halt                    /*   no, die die die */
+41:    bicb3   $0x0f,2(%r1),%r2/* extract addressing mode */
+       bicb3   $0xf0,2(%r1),%r3/* extract register */
+       extzv   $0,$12,6(%fp),%r4/* extract saved mask */
+       cmpb    $0x60,%r2       /* register deferred? */
+       jeql    42f             /*   yes, deal with it */
+       cmpb    $0x90,%r2       /* autoincrement deferred? */
+       jeql    70f             /*   yes, deal with it */
+       halt                    /*   no, die die die */
+
+42:    cmpw    %r4,$0xffc      /* did we save r2-r11? */
+       jneq    50f             /*   no, deal with it */
+       jbc     %r3,%r4,43f     /* is the register in the saved mask? */
 
        /*
-        * Now we save the fixed part of the callframe.
+        * We saved r2-r11, so it's easy to replace the saved register with
+        * the right value by indexing into saved register (offset by 8).
+        */
+       movl    %r0,(20-8)(%fp)[%r3] /* replace address in saved registers */
+       jbr     11b             /* go back and redo call */
+       /*
+        * Must have been called via r0 or r1 which are saved locally.
+        * So move the routine address in the appropriate slot on the stack.
+        */
+43:    movl    %r0,(%sp)[%r3]
+       jbr     11b             /* go back and redo call */
+
+50:    jbs     %r3,%r4,60f     /* is the register in the saved mask? */
+       jbs     %r3,$0x3f,43b   /* is it r0-r5? */
+       /*
+        * The register used for the call was not saved so we need to move
+        * the new function address into it so the re-call will use the new
+        * address.
         */
-1:     clrl    %r4             /* clear condition handler slot */
-       movq    (%sp)+,-(%r0)   /* move FP and PC into place */
-       movq    (%sp)+,-(%r0)   /* move PSW/save-mask/etc + AP into place */
-       movq    %r3,-(%r0)      /* move routine address + cond handle slot */
-       addl3   $4,%r0,%fp      /* get start of new callframe */
-       insv    %r1,$0,$12,6(%fp) /* insert new saved mask */
-       popr    $0x3f           /* restore R0-R5 (cond flags not modified) */
-       subl3   $4,%fp,%sp      /* sp needs to be equal to fp */
-       rsb                     /* and jmp to the routine */
+       pushl   %r0             /* save function address on the stack */
+       ashl    %r5,$1,%r0      /* create a bitmask for the register */
+       popr    %r0             /* pop it off the stack. */
+       jbr     11b             /* and redo the call */
+
+60:    clrl    %r2             /* starting offset into saved registers */
+       clrl    %r5             /* start with register 0 */
+
+61:    cmpl    %r2,%r3         /* is the register to save? */
+       jneq    62f             /*   no, advance to next */
+       movl    %r0,20(%fp)[%r5]/*   yes, save return address in saved reg */
+       jbr     11b             /*        and return the call */
+62:    jbc     %r5,%r4,63f     /* is this register saved? */
+       incl    %r5             /*   yes, account for it */
+63:    incl    %r2             /* increment register number */
+       jbr     61b             /* and loop */
+
+70:    cmpb    %r3,$12
+       blss    71f
+       halt
+
+71:    cmpw    %r4,$0xffc      /* did we save r2-r11? */
+       jneq    72f             /*   no, deal with it */
+       subl2   $4,(20-8)(%fp)[%r3] /* backup incremented register */
+       jbr     11b             /* and redo the call.
+
+72:    jbs     %r3,%r4,80f
+       jbs     %r3,%3f,74f
+       ashl    %r5,$1,%r0      /* create a bitmask for the register */
+       pushr   %r0             /* pop it off the stack. */
+       subl2   $4,(%sp)        /* backup incremented register */
+       popr    %r0             /* pop it off the stack. */
+       jbr     11b             /* and redo the call.
+
+73:    subl2   %4,(%sp)[%r3]   /* backup incremented register */
+       jbr     11b             /* and redo the call.
+
+80:    clrl    %r2             /* starting offset into saved registers */
+       clrl    %r5             /* start with register 0 */
+
+81:    cmpl    %r2,%r3         /* is the register to save? */
+       jneq    82f             /*   no, advance to next */
+       subl    $4,20(%fp)[%r5] /*   yes, backup incremented register */
+       jbr     11b             /*        and return the call */



Home | Main Index | Thread Index | Old Index