ppc64/ppc64asm: add ISA 3.1B support
The new ISA fixes a couple typos, and adds special hashing
instructions to support ROP exploitation.
The hash instructions encode a negative offset in a novel
way which requires a bit of special handling.
Change-Id: I9491e10ac87efe37d93b6efaf7f108ae3a4402fd
Reviewed-on: https://go-review.googlesource.com/c/arch/+/418859
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
Reviewed-by: Joedian Reid <joedian@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Paul Murphy <murp@ibm.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
diff --git a/ppc64/pp64.csv b/ppc64/pp64.csv
index 3150cad..b2aa6b3 100644
--- a/ppc64/pp64.csv
+++ b/ppc64/pp64.csv
@@ -1,4 +1,4 @@
-# POWER ISA 3.1 instruction description.
+# POWER ISA 3.1B instruction description.
#
# This file contains comment lines, each beginning with #,
# followed by entries in CSV format.
@@ -13,8 +13,12 @@
# a list of sequences of the form (,sequence)+. A leading comma is used to signify an
# instruction encoding requiring multiple instruction words.
# The fourth field represents the ISA version where the instruction was introduced as
-# stated in Appendix F. of ISA 3.1
+# stated in Appendix F. of ISA 3.1B
#
+"Hash Check X-form","hashchk RB,offset(RA)","31@0|D@6|RA@11|RB@16|754@21|DX@31|","v3.1B"
+"Hash Check Privileged X-form","hashchkp RB,offset(RA)","31@0|D@6|RA@11|RB@16|690@21|DX@31|","v3.1B"
+"Hash Store X-form","hashst RB,offset(RA)","31@0|D@6|RA@11|RB@16|722@21|DX@31|","v3.1B"
+"Hash Store Privileged X-form","hashstp RB,offset(RA)","31@0|D@6|RA@11|RB@16|658@21|DX@31|","v3.1B"
"Byte-Reverse Doubleword X-form","brd RA,RS","31@0|RS@6|RA@11|///@16|187@21|/@31|","v3.1"
"Byte-Reverse Halfword X-form","brh RA,RS","31@0|RS@6|RA@11|///@16|219@21|/@31|","v3.1"
"Byte-Reverse Word X-form","brw RA,RS","31@0|RS@6|RA@11|///@16|155@21|/@31|","v3.1"
@@ -209,7 +213,7 @@
"VSX Vector bfloat16 GER (Rank-2 Update) Negative multiply, Positive accumulate XX3-form","xvbf16ger2np AT,XA,XB","59@0|AT@6|//@9|A@11|B@16|114@21|AX@29|BX@30|/@31|","v3.1"
"VSX Vector bfloat16 GER (Rank-2 Update) Positive multiply, Negative accumulate XX3-form","xvbf16ger2pn AT,XA,XB","59@0|AT@6|//@9|A@11|B@16|178@21|AX@29|BX@30|/@31|","v3.1"
"VSX Vector bfloat16 GER (Rank-2 Update) Positive multiply, Positive accumulate XX3-form","xvbf16ger2pp AT,XA,XB","59@0|AT@6|//@9|A@11|B@16|50@21|AX@29|BX@30|/@31|","v3.1"
-"VSX Vector Convert bfloat16 to Single-Precision format XX2-form","xvcvbf16spn XT,XB","60@0|T@6|16@11|B@16|475@21|BX@30|TX@31|","v3.1"
+"VSX Vector Convert bfloat16 to Single-Precision format Non-signaling XX2-form","xvcvbf16spn XT,XB","60@0|T@6|16@11|B@16|475@21|BX@30|TX@31|","v3.1"
"VSX Vector Convert with round Single-Precision to bfloat16 format XX2-form","xvcvspbf16 XT,XB","60@0|T@6|17@11|B@16|475@21|BX@30|TX@31|","v3.1"
"VSX Vector 16-bit Floating-Point GER (rank-2 update) XX3-form","xvf16ger2 AT,XA,XB","59@0|AT@6|//@9|A@11|B@16|19@21|AX@29|BX@30|/@31|","v3.1"
"VSX Vector 16-bit Floating-Point GER (rank-2 update) Negative multiply, Negative accumulate XX3-form","xvf16ger2nn AT,XA,XB","59@0|AT@6|//@9|A@11|B@16|210@21|AX@29|BX@30|/@31|","v3.1"
@@ -1034,7 +1038,7 @@
"Add Carrying XO-form","addc RT,RA,RB (OE=0 Rc=0)|addc. RT,RA,RB (OE=0 Rc=1)|addco RT,RA,RB (OE=1 Rc=0)|addco. RT,RA,RB (OE=1 Rc=1)","31@0|RT@6|RA@11|RB@16|OE@21|10@22|Rc@31|","P1"
"Add Extended XO-form","adde RT,RA,RB (OE=0 Rc=0)|adde. RT,RA,RB (OE=0 Rc=1)|addeo RT,RA,RB (OE=1 Rc=0)|addeo. RT,RA,RB (OE=1 Rc=1)","31@0|RT@6|RA@11|RB@16|OE@21|138@22|Rc@31|","P1"
"Add Immediate D-form","addi RT,RA,SI|li RT,SI (RA=0)","14@0|RT@6|RA@11|SI@16|","P1"
-"Add Immediate Carrying D-formy","addic RT,RA,SI","12@0|RT@6|RA@11|SI@16|","P1"
+"Add Immediate Carrying D-form","addic RT,RA,SI","12@0|RT@6|RA@11|SI@16|","P1"
"Add Immediate Carrying and Record D-form","addic. RT,RA,SI","13@0|RT@6|RA@11|SI@16|","P1"
"Add Immediate Shifted D-form","addis RT,RA,SI|lis RT,SI (RA=0)","15@0|RT@6|RA@11|SI@16|","P1"
"Add to Minus One Extended XO-form","addme RT,RA (OE=0 Rc=0)|addme. RT,RA (OE=0 Rc=1)|addmeo RT,RA (OE=1 Rc=0)|addmeo. RT,RA (OE=1 Rc=1)","31@0|RT@6|RA@11|///@16|OE@21|234@22|Rc@31|","P1"
diff --git a/ppc64/ppc64asm/decode.go b/ppc64/ppc64asm/decode.go
index 59bd325..b8d857c 100644
--- a/ppc64/ppc64asm/decode.go
+++ b/ppc64/ppc64asm/decode.go
@@ -22,9 +22,12 @@
// The Args are stored in the same order as the instruction manual.
//
// Prefixed instructions are stored as:
-// prefix << 32 | suffix,
+//
+// prefix << 32 | suffix,
+//
// Regular instructions are:
-// inst << 32
+//
+// inst << 32
type instFormat struct {
Op Op
Mask uint64
@@ -77,6 +80,12 @@
return Label(a.BitFields.ParseSigned(i) << a.Shift)
case TypeOffset:
return Offset(a.BitFields.ParseSigned(i) << a.Shift)
+ case TypeNegOffset:
+ // An oddball encoding of offset for hashchk and similar.
+ // e.g hashchk offset is 0b1111111000000000 | DX << 8 | D << 3
+ off := a.BitFields.ParseSigned(i) << a.Shift
+ neg := int64(-1) << (int(a.Shift) + a.BitFields.NumBits())
+ return Offset(neg | off)
}
}
@@ -98,6 +107,7 @@
TypeImmSigned // signed immediate
TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type
TypeOffset // signed offset in load/store
+ TypeNegOffset // A negative 16 bit value 0b1111111xxxxx000 encoded as 0bxxxxx (e.g in the hashchk instruction)
TypeLast // must be the last one
)
@@ -135,6 +145,8 @@
return "Label"
case TypeOffset:
return "Offset"
+ case TypeNegOffset:
+ return "NegOffset"
}
}
diff --git a/ppc64/ppc64asm/field.go b/ppc64/ppc64asm/field.go
index 13df063..3779446 100644
--- a/ppc64/ppc64asm/field.go
+++ b/ppc64/ppc64asm/field.go
@@ -86,3 +86,12 @@
u, l := bs.parse(i)
return int64(u) << (64 - l) >> (64 - l)
}
+
+// Count the number of bits in the aggregate BitFields
+func (bs BitFields) NumBits() int {
+ num := 0
+ for _, b := range bs {
+ num += int(b.Bits)
+ }
+ return num
+}
diff --git a/ppc64/ppc64asm/field_test.go b/ppc64/ppc64asm/field_test.go
index 01402b5..ce18ad5 100644
--- a/ppc64/ppc64asm/field_test.go
+++ b/ppc64/ppc64asm/field_test.go
@@ -65,26 +65,29 @@
i [2]uint32 // input
u uint64 // unsigned output
s int64 // signed output
+ nb int // Total number of bits in BitField
fail bool // if the check should panic
}{
- {BitFields{{0, 0, 1}}, [2]uint32{0, 0}, 0, 0, true},
- {BitFields{{31, 2, 1}}, [2]uint32{0, 0}, 0, 0, true},
- {BitFields{{31, 1, 1}}, [2]uint32{0, 1}, 1, -1, false},
- {BitFields{{29, 2, 1}}, [2]uint32{0, 0 << 1}, 0, 0, false},
- {BitFields{{29, 2, 1}}, [2]uint32{0, 1 << 1}, 1, 1, false},
- {BitFields{{29, 2, 1}}, [2]uint32{0, 2 << 1}, 2, -2, false},
- {BitFields{{29, 2, 1}}, [2]uint32{0, 3 << 1}, 3, -1, false},
- {BitFields{{0, 32, 1}}, [2]uint32{0, 1<<32 - 1}, 1<<32 - 1, -1, false},
- {BitFields{{16, 3, 1}}, [2]uint32{0, 1 << 15}, 4, -4, false},
- {BitFields{{16, 16, 0}, {16, 16, 1}}, [2]uint32{0x8016, 0x32}, 0x80160032, -0x7FE9FFCE, false},
- {BitFields{{14, 18, 0}, {16, 16, 1}}, [2]uint32{0x38016, 0x32}, 0x380160032, -0x07FE9FFCE, false},
+ {BitFields{{0, 0, 1}}, [2]uint32{0, 0}, 0, 0, 0, true},
+ {BitFields{{31, 2, 1}}, [2]uint32{0, 0}, 0, 0, 2, true},
+ {BitFields{{31, 1, 1}}, [2]uint32{0, 1}, 1, -1, 1, false},
+ {BitFields{{29, 2, 1}}, [2]uint32{0, 0 << 1}, 0, 0, 2, false},
+ {BitFields{{29, 2, 1}}, [2]uint32{0, 1 << 1}, 1, 1, 2, false},
+ {BitFields{{29, 2, 1}}, [2]uint32{0, 2 << 1}, 2, -2, 2, false},
+ {BitFields{{29, 2, 1}}, [2]uint32{0, 3 << 1}, 3, -1, 2, false},
+ {BitFields{{0, 32, 1}}, [2]uint32{0, 1<<32 - 1}, 1<<32 - 1, -1, 32, false},
+ {BitFields{{16, 3, 1}}, [2]uint32{0, 1 << 15}, 4, -4, 3, false},
+ {BitFields{{16, 16, 0}, {16, 16, 1}}, [2]uint32{0x8016, 0x32}, 0x80160032, -0x7FE9FFCE, 32, false},
+ {BitFields{{14, 18, 0}, {16, 16, 1}}, [2]uint32{0x38016, 0x32}, 0x380160032, -0x07FE9FFCE, 34, false},
}
for i, tst := range tests {
var (
- ou uint64
- os int64
+ ou uint64
+ os int64
+ onb int
)
failed := panicOrNot(func() {
+ onb = tst.b.NumBits()
ou = tst.b.Parse(tst.i)
os = tst.b.ParseSigned(tst.i)
})
@@ -99,5 +102,8 @@
if os != tst.s {
t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
}
+ if onb != tst.nb {
+ t.Errorf("case %d: %v.NumBits() returned %d, expected %d", i, tst.b, onb, tst.nb)
+ }
}
}
diff --git a/ppc64/ppc64asm/plan9.go b/ppc64/ppc64asm/plan9.go
index 4bd1c7f..fcb2a12 100644
--- a/ppc64/ppc64asm/plan9.go
+++ b/ppc64/ppc64asm/plan9.go
@@ -83,7 +83,9 @@
STH, STHU,
STW, STWU,
STD, STDU,
- STQ, STFD, STFDU, STFS, STFSU:
+ STFD, STFDU,
+ STFS, STFSU,
+ STQ, HASHST, HASHSTP:
return op + " " + strings.Join(args, ",")
case FCMPU, FCMPO, CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
diff --git a/ppc64/ppc64asm/tables.go b/ppc64/ppc64asm/tables.go
index 8d0a243..8705077 100644
--- a/ppc64/ppc64asm/tables.go
+++ b/ppc64/ppc64asm/tables.go
@@ -1,9 +1,13 @@
-// Code generated by ppc64map -fmt=decoder pp64.csv DO NOT EDIT.
+// Code generated by ppc64map -fmt=decoder ../pp64.csv DO NOT EDIT.
package ppc64asm
const (
_ Op = iota
+ HASHCHK
+ HASHCHKP
+ HASHST
+ HASHSTP
BRD
BRH
BRW
@@ -1420,6 +1424,10 @@
)
var opstr = [...]string{
+ HASHCHK: "hashchk",
+ HASHCHKP: "hashchkp",
+ HASHST: "hashst",
+ HASHSTP: "hashstp",
BRD: "brd",
BRH: "brh",
BRW: "brw",
@@ -2836,9 +2844,10 @@
}
var (
+ ap_Reg_16_20 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{16, 5, 0}}}
+ ap_NegOffset_31_31_6_10_shift3 = &argField{Type: TypeNegOffset, Shift: 3, BitFields: BitFields{{31, 1, 0}, {6, 5, 0}}}
ap_Reg_11_15 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{11, 5, 0}}}
ap_Reg_6_10 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{6, 5, 0}}}
- ap_Reg_16_20 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{16, 5, 0}}}
ap_FPReg_6_10 = &argField{Type: TypeFPReg, Shift: 0, BitFields: BitFields{{6, 5, 0}}}
ap_VecReg_16_20 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{16, 5, 0}}}
ap_VecReg_6_10 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{6, 5, 0}}}
@@ -2942,6 +2951,14 @@
)
var instFormats = [...]instFormat{
+ {HASHCHK, 0xfc0007fe00000000, 0x7c0005e400000000, 0x0, // Hash Check X-form (hashchk RB,offset(RA))
+ [6]*argField{ap_Reg_16_20, ap_NegOffset_31_31_6_10_shift3, ap_Reg_11_15}},
+ {HASHCHKP, 0xfc0007fe00000000, 0x7c00056400000000, 0x0, // Hash Check Privileged X-form (hashchkp RB,offset(RA))
+ [6]*argField{ap_Reg_16_20, ap_NegOffset_31_31_6_10_shift3, ap_Reg_11_15}},
+ {HASHST, 0xfc0007fe00000000, 0x7c0005a400000000, 0x0, // Hash Store X-form (hashst RB,offset(RA))
+ [6]*argField{ap_Reg_16_20, ap_NegOffset_31_31_6_10_shift3, ap_Reg_11_15}},
+ {HASHSTP, 0xfc0007fe00000000, 0x7c00052400000000, 0x0, // Hash Store Privileged X-form (hashstp RB,offset(RA))
+ [6]*argField{ap_Reg_16_20, ap_NegOffset_31_31_6_10_shift3, ap_Reg_11_15}},
{BRD, 0xfc0007fe00000000, 0x7c00017600000000, 0xf80100000000, // Byte-Reverse Doubleword X-form (brd RA,RS)
[6]*argField{ap_Reg_11_15, ap_Reg_6_10}},
{BRH, 0xfc0007fe00000000, 0x7c0001b600000000, 0xf80100000000, // Byte-Reverse Halfword X-form (brh RA,RS)
@@ -3344,7 +3361,7 @@
[6]*argField{ap_MMAReg_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
{XVBF16GER2PP, 0xfc0007f800000000, 0xec00019000000000, 0x60000100000000, // VSX Vector bfloat16 GER (Rank-2 Update) Positive multiply, Positive accumulate XX3-form (xvbf16ger2pp AT,XA,XB)
[6]*argField{ap_MMAReg_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
- {XVCVBF16SPN, 0xfc1f07fc00000000, 0xf010076c00000000, 0x0, // VSX Vector Convert bfloat16 to Single-Precision format XX2-form (xvcvbf16spn XT,XB)
+ {XVCVBF16SPN, 0xfc1f07fc00000000, 0xf010076c00000000, 0x0, // VSX Vector Convert bfloat16 to Single-Precision format Non-signaling XX2-form (xvcvbf16spn XT,XB)
[6]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
{XVCVSPBF16, 0xfc1f07fc00000000, 0xf011076c00000000, 0x0, // VSX Vector Convert with round Single-Precision to bfloat16 format XX2-form (xvcvspbf16 XT,XB)
[6]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
@@ -5334,7 +5351,7 @@
[6]*argField{ap_Reg_6_10, ap_ImmSigned_16_31}},
{ADDI, 0xfc00000000000000, 0x3800000000000000, 0x0, // Add Immediate D-form (addi RT,RA,SI)
[6]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
- {ADDIC, 0xfc00000000000000, 0x3000000000000000, 0x0, // Add Immediate Carrying D-formy (addic RT,RA,SI)
+ {ADDIC, 0xfc00000000000000, 0x3000000000000000, 0x0, // Add Immediate Carrying D-form (addic RT,RA,SI)
[6]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
{ADDICCC, 0xfc00000000000000, 0x3400000000000000, 0x0, // Add Immediate Carrying and Record D-form (addic. RT,RA,SI)
[6]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
diff --git a/ppc64/ppc64asm/testdata/decode.txt b/ppc64/ppc64asm/testdata/decode.txt
index 7bf4355..ef5c90e 100644
--- a/ppc64/ppc64asm/testdata/decode.txt
+++ b/ppc64/ppc64asm/testdata/decode.txt
@@ -873,3 +873,13 @@
7c2311b8| plan9 CFUGED R1,R2,R3
04100016e4820032| gnu .quad 0x4100016e4820032
0612000138820007| gnu .quad 0x612000138820007
+7fe20de5| plan9 HASHCHK -8(R2),R1
+7fe20da5| plan9 HASHST R1,-8(R2)
+7c020de4| plan9 HASHCHK -512(R2),R1
+7c020da4| plan9 HASHST R1,-512(R2)
+7c020de5| plan9 HASHCHK -256(R2),R1
+7c020da5| plan9 HASHST R1,-256(R2)
+7fe115a5| plan9 HASHST R2,-8(R1)
+7fe11525| plan9 HASHSTP R2,-8(R1)
+7fe115e5| plan9 HASHCHK -8(R1),R2
+7fe11565| plan9 HASHCHKP -8(R1),R2
diff --git a/ppc64/ppc64asm/testdata/decode_generated.txt b/ppc64/ppc64asm/testdata/decode_generated.txt
index d8619d7..13345e9 100644
--- a/ppc64/ppc64asm/testdata/decode_generated.txt
+++ b/ppc64/ppc64asm/testdata/decode_generated.txt
@@ -1,3 +1,7 @@
+7e0115e5| gnu hashchk r2,-128(r1)
+7e011565| gnu hashchkp r2,-128(r1)
+7e0115a5| gnu hashst r2,-128(r1)
+7e011525| gnu hashstp r2,-128(r1)
7c610176| gnu brd r1,r3
7c6101b6| gnu brh r1,r3
7c610136| gnu brw r1,r3
@@ -23,9 +27,9 @@
7c611138| gnu pdepd r1,r3,r2
7c611178| gnu pextd r1,r3,r2
0610001688800032| gnu plbz r4,1441842
+60000000| gnu nop
04100016e4800032| gnu pld r4,1441842
06100016c8600032| gnu plfd f3,1441842
-60000000| gnu nop
06100016c0600032| gnu plfs f3,1441842
06100016a8800032| gnu plha r4,1441842
06100016a0800032| gnu plhz r4,1441842
@@ -240,7 +244,6 @@
7f810162| gnu xxmtacc a7
0500000188232a4f| gnu xxpermx vs33,vs35,vs37,vs41,1
7f830162| gnu xxsetaccz a7
-60000000| gnu nop
0500012380234567| gnu xxsplti32dx vs33,1,19088743
0500012380254567| gnu xxspltidp vs33,19088743
0500012380274567| gnu xxspltiw vs33,19088743
@@ -1214,13 +1217,13 @@
7c611079| gnu andc. r1,r3,r2
70610000| gnu andi. r1,r3,0
74610000| gnu andis. r1,r3,0
-48000690| gnu b 0x1a90
+48000690| gnu b 0x1a9c
48000692| gnu ba 0x690
-48000691| gnu bl 0x1a98
+48000691| gnu bl 0x1aa4
48000693| gnu bla 0x690
-40860690| gnu bne cr1,0x1aa0
+40860690| gnu bne cr1,0x1aac
40860692| gnu bnea cr1,0x690
-40860691| gnu bnel cr1,0x1aa8
+40860691| gnu bnel cr1,0x1ab4
40860693| gnu bnela cr1,0x690
4c860420| gnu bnectr cr1
4c860421| gnu bnectrl cr1
diff --git a/ppc64/ppc64map/map.go b/ppc64/ppc64map/map.go
index 31d692d..1e3b1b6 100644
--- a/ppc64/ppc64map/map.go
+++ b/ppc64/ppc64map/map.go
@@ -60,6 +60,7 @@
ISA_V30B
ISA_V30C
ISA_V31
+ ISA_V31B
)
var isaToISA = map[string]isaversion{
@@ -77,6 +78,7 @@
"v3.0B": ISA_V30B,
"v3.0C": ISA_V30C,
"v3.1": ISA_V31,
+ "v3.1B": ISA_V31B,
}
func usage() {
@@ -482,6 +484,18 @@
opr = "BD"
}
+ case "offset":
+ switch inst.Op {
+ // These encode a 6 bit displacement in the format of an X-form opcode.
+ // Allowable displaments are -8 to -8*64 in 8B increments.
+ case "hashchk", "hashchkp", "hashst", "hashstp":
+ typ = asm.TypeNegOffset
+ opr = "DX"
+ opr2 = "D"
+ shift = 3
+
+ }
+
case "XMSK", "YMSK", "PMSK", "IX", "BHRBE":
typ = asm.TypeImmUnsigned
@@ -737,7 +751,12 @@
}
// Some ISA instructions are memops, but are not described like "Load ..." or "Store ..."
-var isMemopMap = map[string]bool{}
+var isMemopMap = map[string]bool{
+ "hashst": true,
+ "hashstp": true,
+ "hashchk": true,
+ "hashchkp": true,
+}
// Does this instruction contain a memory argument (e.g x-form load or d-form store)
func hasMemoryArg(insn *Inst) bool {
@@ -767,7 +786,7 @@
// Does this field require an obj.Addr.Offset?
isImmediate := func(t asm.ArgType) bool {
- return t == asm.TypeImmUnsigned || t == asm.TypeSpReg || t == asm.TypeImmSigned || t == asm.TypeOffset
+ return t == asm.TypeImmUnsigned || t == asm.TypeSpReg || t == asm.TypeImmSigned || t == asm.TypeOffset || t == asm.TypeNegOffset
}
if insn.memOp {
@@ -827,13 +846,26 @@
// Generate a check to verify shifted inputs satisfy their constraints.
// For historical reasons this is not needed for 16 bit values shifted by 16. (i.e SI/UI constants in addis/xoris)
- if atype.Shift != 0 && atype.Shift != 16 && bits != 32 {
+ if atype.Type != asm.TypeNegOffset && atype.Shift != 0 && atype.Shift != 16 && bits != 32 {
arg := argOrder[j] + itype
mod := (1 << atype.Shift) - 1
errCheck += fmt.Sprintf("if %s & 0x%x != 0 {\n", arg, mod)
errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant 0x%%x (%%d) is not a multiple of %d\\n%%v\",%s,%s,p)\n", mod+1, arg, arg)
errCheck += fmt.Sprintf("}\n")
}
+ // NegOffset requires a stronger offset check
+ if atype.Type == asm.TypeNegOffset {
+ arg := argOrder[j] + itype
+ mask := -1 << (atype.BitFields.NumBits() + int(atype.Shift))
+ maskl := mask // Sign bits are implied in this type.
+ mask |= (1 << atype.Shift) - 1
+ min := maskl
+ max := maskl | (^mask)
+ step := 1 << atype.Shift
+ errCheck += fmt.Sprintf("if %s & 0x%x != 0x%x {\n", arg, uint32(mask), uint32(maskl))
+ errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant(%%d) must within the range of [%d,%d] in steps of %d\\n%%v\",%s,p)\n", min, max, step, arg)
+ errCheck += fmt.Sprintf("}\n")
+ }
j++
}
buf.WriteString(errCheck)
@@ -895,6 +927,8 @@
if atype.Shift != 0 {
ret += fmt.Sprintf("%d", atype.Shift)
}
+ case asm.TypeNegOffset: // e.g offset in hashst rb, offset(ra)
+ ret += "N"
default:
log.Fatalf("Unhandled type in insnTypeStr: %v\n", atype)
}
@@ -953,6 +987,14 @@
shift = ""
}
}
+ if f.Type == asm.TypeNegOffset {
+ // This is a hack, but allows hashchk and like to correctly
+ // merge there argument into a C_SOREG memory location type
+ // argument a little later.
+ sign = "S"
+ bits = 16
+ shift = ""
+ }
return fmt.Sprintf("C_%s%d%sCON", sign, bits, shift)
}
insn := ta.Insns[0]
diff --git a/ppc64/ppc64util/hack.h b/ppc64/ppc64util/hack.h
index e7dada2..3fd9f31 100644
--- a/ppc64/ppc64util/hack.h
+++ b/ppc64/ppc64util/hack.h
@@ -129,6 +129,9 @@
#define Rpfx 1
#define SIpfx 0xFFFFFFFE00010007
+// A valid displacement value for the hash check and hash store instructions.
+#define offset -128
+
// These decode as m.fpr* or m.vr*. This is a matter of preference. We
// don't support these mnemonics, and I don't think they improve reading
// disassembled code in most cases. so ignore.