From 910c3a9dfc4ff8ea4c25d725783bce4887d790f2 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Thu, 8 Mar 2018 10:33:14 +0000 Subject: [PATCH] cmd/asm: add ARM64 assembler check for incorrect input Current ARM64 assembler has no check for the invalid value of both shift amount and post-index immediate offset of LD1/ST1. This patch adds the check. This patch also fixes the printing error of register number equals to 31, which should be printed as ZR instead of R31. Test cases are also added. Change-Id: I476235f3ab3a3fc91fe89c5a3149a4d4529c05c7 Reviewed-on: https://go-review.googlesource.com/100255 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang --- src/cmd/asm/internal/asm/testdata/arm64.s | 4 + .../asm/internal/asm/testdata/arm64error.s | 105 +++++++++--------- src/cmd/internal/obj/arm64/asm7.go | 42 +++++++ src/cmd/internal/obj/arm64/list7.go | 56 ++++++---- src/cmd/internal/obj/util.go | 3 +- 5 files changed, 135 insertions(+), 75 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index c97b64ddc85..c53023e6304 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -31,6 +31,9 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 AND R1@>33, R2, R3 ADD R1.UXTB, R2, R3 // 4300218b ADD R1.UXTB<<4, R2, R3 // 4310218b + ADD R2, RSP, RSP // ff63228b + ADD R2.SXTX<<1, RSP, RSP // ffe7228b + ADD ZR.SXTX<<1, R2, R3 // 43e43f8b ADDW R2.SXTW, R10, R12 // 4cc1220b ADD R18.UXTX, R14, R17 // d161328b ADDSW R18.UXTW, R14, R17 // d141322b @@ -39,6 +42,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 SUBW R1.UXTX<<1, R3, R2 // 6264214b SUBS R3.UXTX, R8, R9 // 096123eb SUBSW R17.UXTH, R15, R21 // f521316b + SUBW ZR<<14, R19, R13 // 6d3a1f4b CMP R2.SXTH, R13 // bfa122eb CMN R1.SXTX<<2, R10 // 5fe921ab CMPW R2.UXTH<<3, R11 // 7f2d226b diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 93c3acdc3b4..dcdb4fe1757 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -3,54 +3,59 @@ // license that can be found in the LICENSE file. TEXT errors(SB),$0 - MOVD.P 300(R2), R3 // ERROR "offset out of range [-255,254]" - MOVD.P R3, 344(R2) // ERROR "offset out of range [-255,254]" - VLD1 (R8)(R13), [V2.B16] // ERROR "illegal combination" - VLD1 8(R9), [V2.B16] // ERROR "illegal combination" - VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination" - VST1 [V1.B16], 9(R2) // ERROR "illegal combination" - VLD1 8(R8)(R13), [V2.B16] // ERROR "illegal combination" - ADD R1.UXTB<<5, R2, R3 // ERROR "shift amount out of range 0 to 4" - ADDS R1.UXTX<<7, R2, R3 // ERROR "shift amount out of range 0 to 4" - VMOV V8.D[2], V12.D[1] // ERROR "register element index out of range 0 to 1" - VMOV V8.S[4], V12.S[1] // ERROR "register element index out of range 0 to 3" - VMOV V8.H[8], V12.H[1] // ERROR "register element index out of range 0 to 7" - VMOV V8.B[16], V12.B[1] // ERROR "register element index out of range 0 to 15" - VMOV V8.D[0], V12.S[1] // ERROR "operand mismatch" - VMOV V8.D[0], V12.H[1] // ERROR "operand mismatch" - VMOV V8.D[0], V12.B[1] // ERROR "operand mismatch" - VMOV V8.S[0], V12.H[1] // ERROR "operand mismatch" - VMOV V8.S[0], V12.B[1] // ERROR "operand mismatch" - VMOV V8.H[0], V12.B[1] // ERROR "operand mismatch" - VMOV V8.B[16], R3 // ERROR "register element index out of range 0 to 15" - VMOV V8.H[9], R3 // ERROR "register element index out of range 0 to 7" - VMOV V8.S[4], R3 // ERROR "register element index out of range 0 to 3" - VMOV V8.D[2], R3 // ERROR "register element index out of range 0 to 1" - VDUP V8.B[16], R3.B16 // ERROR "register element index out of range 0 to 15" - VDUP V8.B[17], R3.B8 // ERROR "register element index out of range 0 to 15" - VDUP V8.H[9], R3.H4 // ERROR "register element index out of range 0 to 7" - VDUP V8.H[9], R3.H8 // ERROR "register element index out of range 0 to 7" - VDUP V8.S[4], R3.S2 // ERROR "register element index out of range 0 to 3" - VDUP V8.S[4], R3.S4 // ERROR "register element index out of range 0 to 3" - VDUP V8.D[2], R3.D2 // ERROR "register element index out of range 0 to 1" - VFMLA V1.D2, V12.D2, V3.S2 // ERROR "operand mismatch" - VFMLA V1.S2, V12.S2, V3.D2 // ERROR "operand mismatch" - VFMLA V1.S4, V12.S2, V3.D2 // ERROR "operand mismatch" - VFMLA V1.H4, V12.H4, V3.D2 // ERROR "operand mismatch" - VFMLS V1.S2, V12.S2, V3.S4 // ERROR "operand mismatch" - VFMLS V1.S2, V12.D2, V3.S4 // ERROR "operand mismatch" - VFMLS V1.S2, V12.S4, V3.D2 // ERROR "operand mismatch" - VFMLA V1.B8, V12.B8, V3.B8 // ERROR "invalid arrangement" - VFMLA V1.B16, V12.B16, V3.B16 // ERROR "invalid arrangement" - VFMLA V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" - VFMLA V1.H8, V12.H8, V3.H8 // ERROR "invalid arrangement" - VFMLA V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" - VFMLS V1.B8, V12.B8, V3.B8 // ERROR "invalid arrangement" - VFMLS V1.B16, V12.B16, V3.B16 // ERROR "invalid arrangement" - VFMLS V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" - VFMLS V1.H8, V12.H8, V3.H8 // ERROR "invalid arrangement" - VFMLS V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" - - AND $1, RSP // ERROR "illegal combination" - ANDS $1, R0, RSP // ERROR "illegal combination" + AND $1, RSP // ERROR "illegal combination" + ANDS $1, R0, RSP // ERROR "illegal combination" + MOVD.P 300(R2), R3 // ERROR "offset out of range [-255,254]" + MOVD.P R3, 344(R2) // ERROR "offset out of range [-255,254]" + ADDSW R7->32, R14, R13 // ERROR "shift amount out of range 0 to 31" + BICW R7@>33, R5, R16 // ERROR "shift amount out of range 0 to 31" + ADD R1.UXTB<<5, R2, R3 // ERROR "shift amount out of range 0 to 4" + ADDS R1.UXTX<<7, R2, R3 // ERROR "shift amount out of range 0 to 4" + VLD1 (R8)(R13), [V2.B16] // ERROR "illegal combination" + VLD1 8(R9), [V2.B16] // ERROR "illegal combination" + VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination" + VST1 [V1.B16], 9(R2) // ERROR "illegal combination" + VLD1 8(R8)(R13), [V2.B16] // ERROR "illegal combination" + VMOV V8.D[2], V12.D[1] // ERROR "register element index out of range 0 to 1" + VMOV V8.S[4], V12.S[1] // ERROR "register element index out of range 0 to 3" + VMOV V8.H[8], V12.H[1] // ERROR "register element index out of range 0 to 7" + VMOV V8.B[16], V12.B[1] // ERROR "register element index out of range 0 to 15" + VMOV V8.D[0], V12.S[1] // ERROR "operand mismatch" + VMOV V8.D[0], V12.H[1] // ERROR "operand mismatch" + VMOV V8.D[0], V12.B[1] // ERROR "operand mismatch" + VMOV V8.S[0], V12.H[1] // ERROR "operand mismatch" + VMOV V8.S[0], V12.B[1] // ERROR "operand mismatch" + VMOV V8.H[0], V12.B[1] // ERROR "operand mismatch" + VMOV V8.B[16], R3 // ERROR "register element index out of range 0 to 15" + VMOV V8.H[9], R3 // ERROR "register element index out of range 0 to 7" + VMOV V8.S[4], R3 // ERROR "register element index out of range 0 to 3" + VMOV V8.D[2], R3 // ERROR "register element index out of range 0 to 1" + VDUP V8.B[16], R3.B16 // ERROR "register element index out of range 0 to 15" + VDUP V8.B[17], R3.B8 // ERROR "register element index out of range 0 to 15" + VDUP V8.H[9], R3.H4 // ERROR "register element index out of range 0 to 7" + VDUP V8.H[9], R3.H8 // ERROR "register element index out of range 0 to 7" + VDUP V8.S[4], R3.S2 // ERROR "register element index out of range 0 to 3" + VDUP V8.S[4], R3.S4 // ERROR "register element index out of range 0 to 3" + VDUP V8.D[2], R3.D2 // ERROR "register element index out of range 0 to 1" + VFMLA V1.D2, V12.D2, V3.S2 // ERROR "operand mismatch" + VFMLA V1.S2, V12.S2, V3.D2 // ERROR "operand mismatch" + VFMLA V1.S4, V12.S2, V3.D2 // ERROR "operand mismatch" + VFMLA V1.H4, V12.H4, V3.D2 // ERROR "operand mismatch" + VFMLS V1.S2, V12.S2, V3.S4 // ERROR "operand mismatch" + VFMLS V1.S2, V12.D2, V3.S4 // ERROR "operand mismatch" + VFMLS V1.S2, V12.S4, V3.D2 // ERROR "operand mismatch" + VFMLA V1.B8, V12.B8, V3.B8 // ERROR "invalid arrangement" + VFMLA V1.B16, V12.B16, V3.B16 // ERROR "invalid arrangement" + VFMLA V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" + VFMLA V1.H8, V12.H8, V3.H8 // ERROR "invalid arrangement" + VFMLA V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" + VFMLS V1.B8, V12.B8, V3.B8 // ERROR "invalid arrangement" + VFMLS V1.B16, V12.B16, V3.B16 // ERROR "invalid arrangement" + VFMLS V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" + VFMLS V1.H8, V12.H8, V3.H8 // ERROR "invalid arrangement" + VFMLS V1.H4, V12.H4, V3.H4 // ERROR "invalid arrangement" + VST1.P [V4.S4,V5.S4], 48(R1) // ERROR "invalid post-increment offset" + VST1.P [V4.S4], 8(R1) // ERROR "invalid post-increment offset" + VLD1.P 32(R1), [V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset" + VLD1.P 48(R1), [V7.S4, V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset" RET diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 3b7ad244933..7b940dd58ce 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -2227,6 +2227,41 @@ func (c *ctxt7) checkindex(p *obj.Prog, index, maxindex int) { } } +/* checkoffset checks whether the immediate offset is valid for VLD1.P and VST1.P*/ +func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) { + var offset, list, n int64 + switch as { + case AVLD1: + offset = p.From.Offset + list = p.To.Offset + case AVST1: + offset = p.To.Offset + list = p.From.Offset + default: + c.ctxt.Diag("invalid operation on op %v", p.As) + } + opcode := (list >> 12) & 15 + q := (list >> 30) & 1 + if offset == 0 { + return + } + switch opcode { + case 0x7: + n = 1 // one register + case 0xa: + n = 2 // two registers + case 0x6: + n = 3 // three registers + case 0x2: + n = 4 // four registers + default: + c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p) + } + if !(q == 0 && offset == n*8) && !(q == 1 && offset == n*16) { + c.ctxt.Diag("invalid post-increment offset: %v", p) + } +} + func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 := uint32(0) o2 := uint32(0) @@ -2278,6 +2313,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case 3: /* op R<> 10) & 63 + is64bit := o1 & (1 << 31) + if is64bit == 0 && amount >= 32 { + c.ctxt.Diag("shift amount out of range 0 to 31: %v", p) + } o1 |= uint32(p.From.Offset) /* includes reg, op, etc */ rt := int(p.To.Reg) if p.To.Type == obj.TYPE_NONE { @@ -3634,6 +3674,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 |= 1 << 23 if p.From.Index == 0 { // immediate offset variant + c.checkoffset(p, p.As) o1 |= 0x1f << 16 } else { // register offset variant @@ -3722,6 +3763,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 |= 1 << 23 if p.To.Index == 0 { // immediate offset variant + c.checkoffset(p, p.As) o1 |= 0x1f << 16 } else { // register offset variant diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go index 37c61d22555..266e2baaeef 100644 --- a/src/cmd/internal/obj/arm64/list7.go +++ b/src/cmd/internal/obj/arm64/list7.go @@ -92,6 +92,7 @@ func arrange(a int) string { } func rconv(r int) string { + ext := (r >> 5) & 7 if r == REGG { return "g" } @@ -173,52 +174,52 @@ func rconv(r int) string { case r == REG_PSTL3STRM: return "PSTL3STRM" case REG_UXTB <= r && r < REG_UXTH: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.UXTB<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.UXTB", r&31) + return fmt.Sprintf("%s.UXTB", regname(r)) } case REG_UXTH <= r && r < REG_UXTW: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.UXTH<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.UXTH<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.UXTH", r&31) + return fmt.Sprintf("%s.UXTH", regname(r)) } case REG_UXTW <= r && r < REG_UXTX: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.UXTW<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.UXTW<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.UXTW", r&31) + return fmt.Sprintf("%s.UXTW", regname(r)) } case REG_UXTX <= r && r < REG_SXTB: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.UXTX<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.UXTX<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.UXTX", r&31) + return fmt.Sprintf("%s.UXTX", regname(r)) } case REG_SXTB <= r && r < REG_SXTH: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.SXTB<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.SXTB<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.SXTB", r&31) + return fmt.Sprintf("%s.SXTB", regname(r)) } case REG_SXTH <= r && r < REG_SXTW: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.SXTH<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.SXTH<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.SXTH", r&31) + return fmt.Sprintf("%s.SXTH", regname(r)) } case REG_SXTW <= r && r < REG_SXTX: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.SXTW<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.SXTW<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.SXTW", r&31) + return fmt.Sprintf("%s.SXTW", regname(r)) } case REG_SXTX <= r && r < REG_SPECIAL: - if (r>>5)&7 != 0 { - return fmt.Sprintf("R%d.SXTX<<%d", r&31, (r>>5)&7) + if ext != 0 { + return fmt.Sprintf("%s.SXTX<<%d", regname(r), ext) } else { - return fmt.Sprintf("R%d.SXTX", r&31) + return fmt.Sprintf("%s.SXTX", regname(r)) } case REG_ARNG <= r && r < REG_ELEM: return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15)) @@ -291,3 +292,10 @@ func rlconv(list int64) string { str += "]" return str } + +func regname(r int) string { + if r&31 == 31 { + return "ZR" + } + return fmt.Sprintf("R%d", r&31) +} diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 245e9e9e9b7..9b25231bb41 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -263,7 +263,8 @@ func Dconv(p *Prog, a *Addr) string { } case "arm64": op := ops[((v>>22)&3)<<1:] - str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63) + r := (v >> 16) & 31 + str = fmt.Sprintf("%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63) default: panic("TYPE_SHIFT is not supported on " + objabi.GOARCH) }