mirror of
https://github.com/golang/go
synced 2024-11-23 08:10:03 -07:00
cmd/asm: detect invalid DS form offsets for ppc64x
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>
This commit is contained in:
parent
16db1892d3
commit
7d4cca07d2
8
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
8
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user