Skip to content

Commit a0222ec

Browse files
zhangfanniecherrymui
authored andcommitted
cmd/internal/obj/arm64: fix assemble add/adds/sub/subs/cmp/cmn(extended register) bug
The current code encodes the wrong option value in the binary. The fix reconstructs the function opxrrr() that does not encode the option value into the binary value when arguments is sign or zero-extended register. Add the relevant test cases and negative tests. Fixes #23501 Change-Id: Ie5850ead2ad08d9a235a5664869aac5051762f1f Reviewed-on: https://go-review.googlesource.com/88876 Run-TryBot: Cherry Zhang <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent 5952317 commit a0222ec

File tree

4 files changed

+54
-19
lines changed

4 files changed

+54
-19
lines changed

src/cmd/asm/internal/arch/arm64.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ func arm64RegisterNumber(name string, n int16) (int16, bool) {
123123
// ARM64RegisterExtension parses an ARM64 register with extension or arrangment.
124124
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
125125
rm := uint32(reg)
126+
if isAmount {
127+
if num < 0 || num > 7 {
128+
return errors.New("shift amount out of range")
129+
}
130+
}
126131
switch ext {
127132
case "UXTB":
128133
if !isAmount {
@@ -134,7 +139,7 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
134139
if !isAmount {
135140
return errors.New("invalid register extension")
136141
}
137-
a.Reg = arm64.REG_UXTH + (num & 31) + int16(num<<5)
142+
a.Reg = arm64.REG_UXTH + (reg & 31) + int16(num<<5)
138143
a.Offset = int64(((rm & 31) << 16) | (1 << 13) | (uint32(num) << 10))
139144
case "UXTW":
140145
if !isAmount {

src/cmd/asm/internal/asm/testdata/arm64.s

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,20 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
2929
ADD R1<<22, R2, R3
3030
ADD R1->33, R2, R3
3131
AND R1@>33, R2, R3
32-
ADD R1.UXTB, R2, R3 // 4360218b
33-
ADD R1.UXTB<<4, R2, R3 // 4370218b
32+
ADD R1.UXTB, R2, R3 // 4300218b
33+
ADD R1.UXTB<<4, R2, R3 // 4310218b
34+
ADDW R2.SXTW, R10, R12 // 4cc1220b
35+
ADD R18.UXTX, R14, R17 // d161328b
36+
ADDSW R18.UXTW, R14, R17 // d141322b
37+
ADDS R12.SXTX, R3, R1 // 61e02cab
38+
SUB R19.UXTH<<4, R2, R21 // 553033cb
39+
SUBW R1.UXTX<<1, R3, R2 // 6264214b
40+
SUBS R3.UXTX, R8, R9 // 096123eb
41+
SUBSW R17.UXTH, R15, R21 // f521316b
42+
CMP R2.SXTH, R13 // bfa122eb
43+
CMN R1.SXTX<<2, R10 // 5fe921ab
44+
CMPW R2.UXTH<<3, R11 // 7f2d226b
45+
CMNW R1.SXTB, R9 // 3f81212b
3446
VADDP V1.B16, V2.B16, V3.B16 // 43bc214e
3547
VADDP V1.S4, V2.S4, V3.S4 // 43bca14e
3648
VADDP V1.D2, V2.D2, V3.D2 // 43bce14e

src/cmd/asm/internal/asm/testdata/arm64error.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ TEXT errors(SB),$0
1010
VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination"
1111
VST1 [V1.B16], 9(R2) // ERROR "illegal combination"
1212
VLD1 8(R8)(R13), [V2.B16] // ERROR "illegal combination"
13+
ADD R1.UXTB<<5, R2, R3 // ERROR "shift amount out of range 0 to 4"
14+
ADDS R1.UXTX<<7, R2, R3 // ERROR "shift amount out of range 0 to 4"
1315
RET

src/cmd/internal/obj/arm64/asm7.go

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,7 +2362,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
23622362
r = rt
23632363
}
23642364
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
2365-
o2 = c.opxrrr(p, p.As)
2365+
o2 = c.opxrrr(p, p.As, false)
23662366
o2 |= REGTMP & 31 << 16
23672367
o2 |= LSL0_64
23682368
} else {
@@ -2591,11 +2591,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
25912591
o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
25922592

25932593
case 27: /* op Rm<<n[,Rn],Rd (extended register) */
2594-
o1 = c.opxrrr(p, p.As)
25952594

25962595
if (p.From.Reg-obj.RBaseARM64)&REG_EXT != 0 {
2596+
amount := (p.From.Reg >> 5) & 7
2597+
if amount > 4 {
2598+
c.ctxt.Diag("shift amount out of range 0 to 4: %v", p)
2599+
}
2600+
o1 = c.opxrrr(p, p.As, true)
25972601
o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
25982602
} else {
2603+
o1 = c.opxrrr(p, p.As, false)
25992604
o1 |= uint32(p.From.Reg&31) << 16
26002605
}
26012606
rt := int(p.To.Reg)
@@ -2755,7 +2760,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
27552760
if !(o1 != 0) {
27562761
break
27572762
}
2758-
o2 = c.opxrrr(p, AADD)
2763+
o2 = c.opxrrr(p, AADD, false)
27592764
o2 |= REGTMP & 31 << 16
27602765
o2 |= LSL0_64
27612766
r := int(p.From.Reg)
@@ -3122,7 +3127,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
31223127
r = rt
31233128
}
31243129
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
3125-
o2 = c.opxrrr(p, p.As)
3130+
o2 = c.opxrrr(p, p.As, false)
31263131
o2 |= REGTMP & 31 << 16
31273132
o2 |= LSL0_64
31283133
} else {
@@ -3373,7 +3378,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
33733378
}
33743379

33753380
o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
3376-
o2 = c.opxrrr(p, AADD)
3381+
o2 = c.opxrrr(p, AADD, false)
33773382
o2 |= (REGTMP & 31) << 16
33783383
o2 |= uint32(r&31) << 5
33793384
o2 |= uint32(REGTMP & 31)
@@ -3426,7 +3431,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
34263431
o3 |= 2 << 23
34273432
}
34283433
o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
3429-
o2 = c.opxrrr(p, AADD)
3434+
o2 = c.opxrrr(p, AADD, false)
34303435
o2 |= REGTMP & 31 << 16
34313436
o2 |= uint32(r&31) << 5
34323437
o2 |= uint32(REGTMP & 31)
@@ -4518,33 +4523,44 @@ func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 {
45184523
}
45194524

45204525
/*
4521-
* add/subtract extended register
4526+
* add/subtract sign or zero-extended register
45224527
*/
4523-
func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As) uint32 {
4528+
func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 {
4529+
extension := uint32(0)
4530+
if !extend {
4531+
switch a {
4532+
case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS:
4533+
extension = LSL0_64
4534+
4535+
case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW:
4536+
extension = LSL0_32
4537+
}
4538+
}
4539+
45244540
switch a {
45254541
case AADD:
4526-
return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
4542+
return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45274543

45284544
case AADDW:
4529-
return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
4545+
return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45304546

45314547
case ACMN, AADDS:
4532-
return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
4548+
return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45334549

45344550
case ACMNW, AADDSW:
4535-
return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
4551+
return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45364552

45374553
case ASUB:
4538-
return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
4554+
return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45394555

45404556
case ASUBW:
4541-
return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
4557+
return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45424558

45434559
case ACMP, ASUBS:
4544-
return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
4560+
return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45454561

45464562
case ACMPW, ASUBSW:
4547-
return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
4563+
return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
45484564
}
45494565

45504566
c.ctxt.Diag("bad opxrrr %v\n%v", a, p)

0 commit comments

Comments
 (0)