]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm: detect invalid DS form offsets for ppc64x
authorLynn Boger <laboger@linux.vnet.ibm.com>
Wed, 12 Apr 2017 18:22:16 +0000 (14:22 -0400)
committerLynn Boger <laboger@linux.vnet.ibm.com>
Mon, 17 Apr 2017 21:24:35 +0000 (21:24 +0000)
While debugging a recent regression it was discovered that
the assembler for ppc64x was not always generating the correct
instruction for DS form loads and stores.  When an instruction
is DS form then the offset must be a multiple of 4, and if it
isn't then bits outside the offset field were being incorrectly
set resulting in unexpected and incorrect instructions.

This change adds a check to determine when the opcode is DS form
and then verifies that the offset is a multiple of 4 before
generating the instruction, otherwise logs an error.

This also changes a few asm files that were using unaligned offsets
for DS form loads and stores.  In the runtime package these were
instructions intended to cause a crash so using aligned or unaligned
offsets doesn't change that behavior.

Change-Id: Ie3a7e1e65dcc9933b54de7a46a054da8459cb56f
Reviewed-on: https://go-review.googlesource.com/40476
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
src/cmd/asm/internal/asm/testdata/ppc64.s
src/cmd/internal/obj/ppc64/asm9.go
src/runtime/asm_ppc64x.s
src/runtime/sys_linux_ppc64x.s

index 14b0de127146287282668104803ddd25a6f8bbe4..e26659305024661d73fadf8104a6be0a216e9e58 100644 (file)
@@ -24,7 +24,7 @@ TEXT foo(SB),DUPOK|NOSPLIT,$0
 //     {
 //             outcode(int($1), &$2, 0, &$4);
 //     }
-       MOVW    foo<>+3(SB), R2
+       MOVW    foo<>+4(SB), R2
        MOVW    16(R1), R2
 
 //     LMOVW regaddr ',' rreg
@@ -61,7 +61,7 @@ TEXT foo(SB),DUPOK|NOSPLIT,$0
 //     {
 //             outcode(int($1), &$2, 0, &$4);
 //     }
-       FMOVD   foo<>+3(SB), F2
+       FMOVD   foo<>+4(SB), F2
        FMOVD   16(R1), F2
 
 //     LFMOV regaddr ',' freg
@@ -86,7 +86,7 @@ TEXT foo(SB),DUPOK|NOSPLIT,$0
 //     {
 //             outcode(int($1), &$2, 0, &$4);
 //     }
-       FMOVD   F2, foo<>+3(SB)
+       FMOVD   F2, foo<>+4(SB)
        FMOVD   F2, 16(R1)
 
 //     LFMOV freg ',' regaddr
@@ -132,7 +132,7 @@ TEXT foo(SB),DUPOK|NOSPLIT,$0
 //     {
 //             outcode(int($1), &$2, 0, &$4);
 //     }
-       FMOVD   F1, foo<>+3(SB)
+       FMOVD   F1, foo<>+4(SB)
        FMOVD   F1, 16(R2)
 
 //     LMOVW freg ',' regaddr
index 2169416b611640c3304ea73c3f0c77e7ab131d50..65c1a2b2cbe8a20fe1eef4e365c1b5de1257f61e 100644 (file)
@@ -1985,29 +1985,48 @@ const (
        DS_FORM
 )
 
-// opform returns the form (D_FORM or DS_FORM) of an instruction. Used to decide on
-// which relocation to use with a load or store and only supports the needed
-// instructions.
+// This function determines when a non-indexed load or store is D or
+// DS form for use in finding the size of the offset field in the instruction.
+// The size is needed when setting the offset value in the instruction
+// and when generating relocation for that field.
+// DS form instructions include: ld, ldu, lwa, std, stdu.  All other
+// loads and stores with an offset field are D form.  This function should
+// only be called with the same opcodes as are handled by opstore and opload.
 func (c *ctxt9) opform(insn uint32) int {
        switch insn {
        default:
                c.ctxt.Diag("bad insn in loadform: %x", insn)
        case OPVCC(58, 0, 0, 0), // ld
+               OPVCC(58, 0, 0, 1),        // ldu
                OPVCC(58, 0, 0, 0) | 1<<1, // lwa
-               OPVCC(62, 0, 0, 0):        // std
+               OPVCC(62, 0, 0, 0),        // std
+               OPVCC(62, 0, 0, 1):        //stdu
                return DS_FORM
        case OP_ADDI, // add
                OPVCC(32, 0, 0, 0), // lwz
-               OPVCC(42, 0, 0, 0), // lha
-               OPVCC(40, 0, 0, 0), // lhz
+               OPVCC(33, 0, 0, 0), // lwzu
                OPVCC(34, 0, 0, 0), // lbz
-               OPVCC(50, 0, 0, 0), // lfd
+               OPVCC(35, 0, 0, 0), // lbzu
+               OPVCC(40, 0, 0, 0), // lhz
+               OPVCC(41, 0, 0, 0), // lhzu
+               OPVCC(42, 0, 0, 0), // lha
+               OPVCC(43, 0, 0, 0), // lhau
+               OPVCC(46, 0, 0, 0), // lmw
                OPVCC(48, 0, 0, 0), // lfs
+               OPVCC(49, 0, 0, 0), // lfsu
+               OPVCC(50, 0, 0, 0), // lfd
+               OPVCC(51, 0, 0, 0), // lfdu
                OPVCC(36, 0, 0, 0), // stw
-               OPVCC(44, 0, 0, 0), // sth
+               OPVCC(37, 0, 0, 0), // stwu
                OPVCC(38, 0, 0, 0), // stb
+               OPVCC(39, 0, 0, 0), // stbu
+               OPVCC(44, 0, 0, 0), // sth
+               OPVCC(45, 0, 0, 0), // sthu
+               OPVCC(47, 0, 0, 0), // stmw
+               OPVCC(52, 0, 0, 0), // stfs
+               OPVCC(53, 0, 0, 0), // stfsu
                OPVCC(54, 0, 0, 0), // stfd
-               OPVCC(52, 0, 0, 0): // stfs
+               OPVCC(55, 0, 0, 0): // stfdu
                return D_FORM
        }
        return 0
@@ -2268,7 +2287,12 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        if int32(int16(v)) != v {
                                log.Fatalf("mishandled instruction %v", p)
                        }
-                       o1 = AOP_IRR(c.opstore(p.As), uint32(p.From.Reg), uint32(r), uint32(v))
+                       // Offsets in DS form stores must be a multiple of 4
+                       inst := c.opstore(p.As)
+                       if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                               log.Fatalf("invalid offset for DS form load/store %v", p)
+                       }
+                       o1 = AOP_IRR(inst, uint32(p.From.Reg), uint32(r), uint32(v))
                }
 
        case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
@@ -2294,7 +2318,12 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        if int32(int16(v)) != v {
                                log.Fatalf("mishandled instruction %v", p)
                        }
-                       o1 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(r), uint32(v))
+                       // Offsets in DS form loads must be a multiple of 4
+                       inst := c.opload(p.As)
+                       if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                               log.Fatalf("invalid offset for DS form load/store %v", p)
+                       }
+                       o1 = AOP_IRR(inst, uint32(p.To.Reg), uint32(r), uint32(v))
                }
 
        case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
@@ -2789,8 +2818,13 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        r = int(o.param)
                }
+               // Offsets in DS form stores must be a multiple of 4
+               inst := c.opstore(p.As)
+               if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                       log.Fatalf("invalid offset for DS form load/store %v", p)
+               }
                o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
-               o2 = AOP_IRR(c.opstore(p.As), uint32(p.From.Reg), REGTMP, uint32(v))
+               o2 = AOP_IRR(inst, uint32(p.From.Reg), REGTMP, uint32(v))
 
        case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
                v := c.regoff(&p.From)
@@ -3120,19 +3154,34 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
        /* relocation operations */
        case 74:
                v := c.vregoff(&p.To)
-               o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, c.opstore(p.As))
+               // Offsets in DS form stores must be a multiple of 4
+               inst := c.opstore(p.As)
+               if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                       log.Fatalf("invalid offset for DS form load/store %v", p)
+               }
+               o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst)
 
        //if(dlm) reloc(&p->to, p->pc, 1);
 
        case 75:
                v := c.vregoff(&p.From)
-               o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, c.opload(p.As))
+               // Offsets in DS form loads must be a multiple of 4
+               inst := c.opload(p.As)
+               if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                       log.Fatalf("invalid offset for DS form load/store %v", p)
+               }
+               o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
 
        //if(dlm) reloc(&p->from, p->pc, 1);
 
        case 76:
                v := c.vregoff(&p.From)
-               o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, c.opload(p.As))
+               // Offsets in DS form loads must be a multiple of 4
+               inst := c.opload(p.As)
+               if c.opform(inst) == DS_FORM && v&0x3 != 0 {
+                       log.Fatalf("invalid offset for DS form load/store %v", p)
+               }
+               o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst)
                o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
                //if(dlm) reloc(&p->from, p->pc, 1);
index caa000bb56d239470ef6164c9369cda3987e81a2..616861ea7d9d58e4ece6030efe06c20092100ded 100644 (file)
@@ -85,14 +85,14 @@ nocgo:
        // start this M
        BL      runtime·mstart(SB)
 
-       MOVD    R0, 1(R0)
+       MOVD    R0, 0(R0)
        RET
 
 DATA   runtime·mainPC+0(SB)/8,$runtime·main(SB)
 GLOBL  runtime·mainPC(SB),RODATA,$8
 
 TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
-       MOVD    R0, 2(R0) // TODO: TD
+       MOVD    R0, 0(R0) // TODO: TD
        RET
 
 TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
index b43bda1ef2e218c9734ebc7a0d2374845c6cf846..ef7dab21b7576e9c7f0d65de056c6a3f9ff30d84 100644 (file)
@@ -189,7 +189,7 @@ TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
        MOVW    size+24(FP), R6
        SYSCALL $SYS_rt_sigprocmask
        BVC     2(PC)
-       MOVD    R0, 0xf1(R0)    // crash
+       MOVD    R0, 0xf0(R0)    // crash
        RET
 
 TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
@@ -273,7 +273,7 @@ TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
        MOVD    n+8(FP), R4
        SYSCALL $SYS_munmap
        BVC     2(PC)
-       MOVD    R0, 0xf3(R0)
+       MOVD    R0, 0xf0(R0)
        RET
 
 TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
@@ -366,7 +366,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
        MOVD    old+8(FP), R4
        SYSCALL $SYS_sigaltstack
        BVC     2(PC)
-       MOVD    R0, 0xf1(R0)  // crash
+       MOVD    R0, 0xf0(R0)  // crash
        RET
 
 TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0