Commit 1f5a0e8c authored by fanzha02's avatar fanzha02 Committed by Brad Fitzpatrick

cmd/vendor/golang.org/x/arch: pull updates from x repo

Vendor from golang.org/x/arch repo.  Pull in commits that update
arm64, arm, ppc64 and x86 directories (the latest commit 9111c30).

Change-Id: I2b4b3ea9662e69bcf0eeee9c6aba0118175524df
Reviewed-on: https://go-review.googlesource.com/107695
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent c2a53b1b
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"encoding/hex" "encoding/hex"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
...@@ -196,7 +197,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, ...@@ -196,7 +197,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name() file = f.Name()
f.Seek(start, 0) f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f) w := bufio.NewWriter(f)
defer w.Flush() defer w.Flush()
size = 0 size = 0
......
...@@ -192,7 +192,7 @@ func parseContinuation(line []byte, enc []byte) []byte { ...@@ -192,7 +192,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start // describing a text segment that starts at start
// and extends for size bytes. // and extends for size bytes.
func writeELF32(f *os.File, size int) error { func writeELF32(f *os.File, size int) error {
f.Seek(0, 0) f.Seek(0, io.SeekStart)
var hdr elf.Header32 var hdr elf.Header32
var prog elf.Prog32 var prog elf.Prog32
var sect elf.Section32 var sect elf.Section32
......
...@@ -96,34 +96,24 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -96,34 +96,24 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// Move addressing mode into opcode suffix. // Move addressing mode into opcode suffix.
suffix := "" suffix := ""
switch inst.Op &^ 15 { switch inst.Op &^ 15 {
case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ: case PLD, PLI, PLD_W:
mem, _ := inst.Args[1].(Mem) if mem, ok := inst.Args[0].(Mem); ok {
switch mem.Mode { args[0], suffix = memOpTrans(mem)
case AddrOffset, AddrLDM: } else {
// no suffix panic(fmt.Sprintf("illegal instruction: %v", inst))
case AddrPreIndex, AddrLDM_WB:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
}
off := ""
if mem.Offset != 0 {
off = fmt.Sprintf("%#x", mem.Offset)
}
base := fmt.Sprintf("(R%d)", int(mem.Base))
index := ""
if mem.Sign != 0 {
sign := ""
if mem.Sign < 0 {
suffix += ".U"
} }
shift := "" case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ, LDREX_EQ, LDREXH_EQ, LDREXB_EQ:
if mem.Count != 0 { if mem, ok := inst.Args[1].(Mem); ok {
shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count) args[1], suffix = memOpTrans(mem)
} else {
panic(fmt.Sprintf("illegal instruction: %v", inst))
} }
index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift) case SWP_EQ, SWP_B_EQ, STREX_EQ, STREXB_EQ, STREXH_EQ:
if mem, ok := inst.Args[2].(Mem); ok {
args[2], suffix = memOpTrans(mem)
} else {
panic(fmt.Sprintf("illegal instruction: %v", inst))
} }
args[1] = off + base + index
} }
// Reverse args, placing dest last. // Reverse args, placing dest last.
...@@ -135,35 +125,35 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -135,35 +125,35 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
case SMLAWT_EQ, SMLAWB_EQ, MLA_EQ, MLA_S_EQ, MLS_EQ, SMMLA_EQ, SMMLS_EQ, SMLABB_EQ, SMLATB_EQ, SMLABT_EQ, SMLATT_EQ, SMLAD_EQ, SMLAD_X_EQ, SMLSD_EQ, SMLSD_X_EQ: case SMLAWT_EQ, SMLAWB_EQ, MLA_EQ, MLA_S_EQ, MLS_EQ, SMMLA_EQ, SMMLS_EQ, SMLABB_EQ, SMLATB_EQ, SMLABT_EQ, SMLATT_EQ, SMLAD_EQ, SMLAD_X_EQ, SMLSD_EQ, SMLSD_X_EQ:
args = []string{args[1], args[2], args[0], args[3]} args = []string{args[1], args[2], args[0], args[3]}
} }
// For STREX like instructions, the memory operands comes first.
switch inst.Op &^ 15 {
case STREX_EQ, STREXB_EQ, STREXH_EQ, SWP_EQ, SWP_B_EQ:
args = []string{args[1], args[0], args[2]}
}
// special process for FP instructions
op, args = fpTrans(&inst, op, args)
// LDR/STR like instructions -> MOV like
switch inst.Op &^ 15 { switch inst.Op &^ 15 {
case MOV_EQ: case MOV_EQ:
op = "MOVW" + op[3:] op = "MOVW" + op[3:]
case LDR_EQ, MSR_EQ, MRS_EQ:
case LDR_EQ:
op = "MOVW" + op[3:] + suffix op = "MOVW" + op[3:] + suffix
case LDRB_EQ: case VMRS_EQ, VMSR_EQ:
op = "MOVW" + op[4:] + suffix
case LDRB_EQ, UXTB_EQ:
op = "MOVBU" + op[4:] + suffix op = "MOVBU" + op[4:] + suffix
case LDRSB_EQ: case LDRSB_EQ:
op = "MOVBS" + op[5:] + suffix op = "MOVBS" + op[5:] + suffix
case LDRH_EQ: case SXTB_EQ:
op = "MOVBS" + op[4:] + suffix
case LDRH_EQ, UXTH_EQ:
op = "MOVHU" + op[4:] + suffix op = "MOVHU" + op[4:] + suffix
case LDRSH_EQ: case LDRSH_EQ:
op = "MOVHS" + op[5:] + suffix op = "MOVHS" + op[5:] + suffix
case VLDR_EQ: case SXTH_EQ:
switch { op = "MOVHS" + op[4:] + suffix
case strings.HasPrefix(args[1], "D"): // VLDR.F64
op = "MOVD" + op[4:] + suffix
args[1] = "F" + args[1][1:] // Dx -> Fx
case strings.HasPrefix(args[1], "S"): // VLDR.F32
op = "MOVF" + op[4:] + suffix
if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
}
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
case STR_EQ: case STR_EQ:
op = "MOVW" + op[3:] + suffix op = "MOVW" + op[3:] + suffix
args[0], args[1] = args[1], args[0] args[0], args[1] = args[1], args[0]
...@@ -174,19 +164,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -174,19 +164,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
op = "MOVH" + op[4:] + suffix op = "MOVH" + op[4:] + suffix
args[0], args[1] = args[1], args[0] args[0], args[1] = args[1], args[0]
case VSTR_EQ: case VSTR_EQ:
switch {
case strings.HasPrefix(args[1], "D"): // VSTR.F64
op = "MOVD" + op[4:] + suffix
args[1] = "F" + args[1][1:] // Dx -> Fx
case strings.HasPrefix(args[1], "S"): // VSTR.F32
op = "MOVF" + op[4:] + suffix
if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
}
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
args[0], args[1] = args[1], args[0] args[0], args[1] = args[1], args[0]
default:
op = op + suffix
} }
if args != nil { if args != nil {
...@@ -266,3 +246,153 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -266,3 +246,153 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
} }
return strings.ToUpper(arg.String()) return strings.ToUpper(arg.String())
} }
// convert memory operand from GNU syntax to Plan 9 syntax, for example,
// [r5] -> (R5)
// [r6, #4080] -> 0xff0(R6)
// [r2, r0, ror #1] -> (R2)(R0@>1)
// inst [r2, -r0, ror #1] -> INST.U (R2)(R0@>1)
// input:
// a memory operand
// return values:
// corresponding memory operand in Plan 9 syntax
// .W/.P/.U suffix
func memOpTrans(mem Mem) (string, string) {
suffix := ""
switch mem.Mode {
case AddrOffset, AddrLDM:
// no suffix
case AddrPreIndex, AddrLDM_WB:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
}
off := ""
if mem.Offset != 0 {
off = fmt.Sprintf("%#x", mem.Offset)
}
base := fmt.Sprintf("(R%d)", int(mem.Base))
index := ""
if mem.Sign != 0 {
sign := ""
if mem.Sign < 0 {
suffix += ".U"
}
shift := ""
if mem.Count != 0 {
shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
}
index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
}
return off + base + index, suffix
}
type goFPInfo struct {
op Op
transArgs []int // indexes of arguments which need transformation
gnuName string // instruction name in GNU syntax
goName string // instruction name in Plan 9 syntax
}
var fpInst []goFPInfo = []goFPInfo{
{VADD_EQ_F32, []int{2, 1, 0}, "VADD", "ADDF"},
{VADD_EQ_F64, []int{2, 1, 0}, "VADD", "ADDD"},
{VSUB_EQ_F32, []int{2, 1, 0}, "VSUB", "SUBF"},
{VSUB_EQ_F64, []int{2, 1, 0}, "VSUB", "SUBD"},
{VMUL_EQ_F32, []int{2, 1, 0}, "VMUL", "MULF"},
{VMUL_EQ_F64, []int{2, 1, 0}, "VMUL", "MULD"},
{VNMUL_EQ_F32, []int{2, 1, 0}, "VNMUL", "NMULF"},
{VNMUL_EQ_F64, []int{2, 1, 0}, "VNMUL", "NMULD"},
{VMLA_EQ_F32, []int{2, 1, 0}, "VMLA", "MULAF"},
{VMLA_EQ_F64, []int{2, 1, 0}, "VMLA", "MULAD"},
{VMLS_EQ_F32, []int{2, 1, 0}, "VMLS", "MULSF"},
{VMLS_EQ_F64, []int{2, 1, 0}, "VMLS", "MULSD"},
{VNMLA_EQ_F32, []int{2, 1, 0}, "VNMLA", "NMULAF"},
{VNMLA_EQ_F64, []int{2, 1, 0}, "VNMLA", "NMULAD"},
{VNMLS_EQ_F32, []int{2, 1, 0}, "VNMLS", "NMULSF"},
{VNMLS_EQ_F64, []int{2, 1, 0}, "VNMLS", "NMULSD"},
{VDIV_EQ_F32, []int{2, 1, 0}, "VDIV", "DIVF"},
{VDIV_EQ_F64, []int{2, 1, 0}, "VDIV", "DIVD"},
{VNEG_EQ_F32, []int{1, 0}, "VNEG", "NEGF"},
{VNEG_EQ_F64, []int{1, 0}, "VNEG", "NEGD"},
{VABS_EQ_F32, []int{1, 0}, "VABS", "ABSF"},
{VABS_EQ_F64, []int{1, 0}, "VABS", "ABSD"},
{VSQRT_EQ_F32, []int{1, 0}, "VSQRT", "SQRTF"},
{VSQRT_EQ_F64, []int{1, 0}, "VSQRT", "SQRTD"},
{VCMP_EQ_F32, []int{1, 0}, "VCMP", "CMPF"},
{VCMP_EQ_F64, []int{1, 0}, "VCMP", "CMPD"},
{VCMP_E_EQ_F32, []int{1, 0}, "VCMP.E", "CMPF"},
{VCMP_E_EQ_F64, []int{1, 0}, "VCMP.E", "CMPD"},
{VLDR_EQ, []int{1}, "VLDR", "MOV"},
{VSTR_EQ, []int{1}, "VSTR", "MOV"},
{VMOV_EQ_F32, []int{1, 0}, "VMOV", "MOVF"},
{VMOV_EQ_F64, []int{1, 0}, "VMOV", "MOVD"},
{VMOV_EQ_32, []int{1, 0}, "VMOV", "MOVW"},
{VMOV_EQ, []int{1, 0}, "VMOV", "MOVW"},
{VCVT_EQ_F64_F32, []int{1, 0}, "VCVT", "MOVFD"},
{VCVT_EQ_F32_F64, []int{1, 0}, "VCVT", "MOVDF"},
{VCVT_EQ_F32_U32, []int{1, 0}, "VCVT", "MOVWF.U"},
{VCVT_EQ_F32_S32, []int{1, 0}, "VCVT", "MOVWF"},
{VCVT_EQ_S32_F32, []int{1, 0}, "VCVT", "MOVFW"},
{VCVT_EQ_U32_F32, []int{1, 0}, "VCVT", "MOVFW.U"},
{VCVT_EQ_F64_U32, []int{1, 0}, "VCVT", "MOVWD.U"},
{VCVT_EQ_F64_S32, []int{1, 0}, "VCVT", "MOVWD"},
{VCVT_EQ_S32_F64, []int{1, 0}, "VCVT", "MOVDW"},
{VCVT_EQ_U32_F64, []int{1, 0}, "VCVT", "MOVDW.U"},
}
// convert FP instructions from GNU syntax to Plan 9 syntax, for example,
// vadd.f32 s0, s3, s4 -> ADDF F0, S3, F2
// vsub.f64 d0, d2, d4 -> SUBD F0, F2, F4
// vldr s2, [r11] -> MOVF (R11), F1
// inputs: instruction name and arguments in GNU syntax
// return values: corresponding instruction name and arguments in Plan 9 syntax
func fpTrans(inst *Inst, op string, args []string) (string, []string) {
for _, fp := range fpInst {
if inst.Op&^15 == fp.op {
// remove gnu syntax suffixes
op = strings.Replace(op, ".F32", "", -1)
op = strings.Replace(op, ".F64", "", -1)
op = strings.Replace(op, ".S32", "", -1)
op = strings.Replace(op, ".U32", "", -1)
op = strings.Replace(op, ".32", "", -1)
// compose op name
if fp.op == VLDR_EQ || fp.op == VSTR_EQ {
switch {
case strings.HasPrefix(args[fp.transArgs[0]], "D"):
op = "MOVD" + op[len(fp.gnuName):]
case strings.HasPrefix(args[fp.transArgs[0]], "S"):
op = "MOVF" + op[len(fp.gnuName):]
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
} else {
op = fp.goName + op[len(fp.gnuName):]
}
// transform registers
for ix, ri := range fp.transArgs {
switch {
case strings.HasSuffix(args[ri], "[1]"): // MOVW Rx, Dy[1]
break
case strings.HasSuffix(args[ri], "[0]"): // Dx[0] -> Fx
args[ri] = strings.Replace(args[ri], "[0]", "", -1)
fallthrough
case strings.HasPrefix(args[ri], "D"): // Dx -> Fx
args[ri] = "F" + args[ri][1:]
case strings.HasPrefix(args[ri], "S"):
if inst.Args[ix].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[ri] = fmt.Sprintf("F%d", (inst.Args[ix].(Reg)-S0)/2)
}
case strings.HasPrefix(args[ri], "$"): // CMPF/CMPD $0, Fx
break
case strings.HasPrefix(args[ri], "R"): // MOVW Rx, Dy[1]
break
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
}
break
}
}
return op, args
}
...@@ -7,12 +7,14 @@ package arm64asm ...@@ -7,12 +7,14 @@ package arm64asm
import ( import (
"encoding/hex" "encoding/hex"
"io/ioutil" "io/ioutil"
"path/filepath"
"strings" "strings"
"testing" "testing"
) )
func TestDecode(t *testing.T) { func testDecode(t *testing.T, syntax string) {
data, err := ioutil.ReadFile("testdata/cases.txt") input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -25,7 +27,7 @@ func TestDecode(t *testing.T) { ...@@ -25,7 +27,7 @@ func TestDecode(t *testing.T) {
if line == "" || strings.HasPrefix(line, "#") { if line == "" || strings.HasPrefix(line, "#") {
continue continue
} }
f := strings.SplitN(line, "\t", 3) f := strings.SplitN(line, "\t", 2)
i := strings.Index(f[0], "|") i := strings.Index(f[0], "|")
if i < 0 { if i < 0 {
t.Errorf("parsing %q: missing | separator", f[0]) t.Errorf("parsing %q: missing | separator", f[0])
...@@ -39,7 +41,7 @@ func TestDecode(t *testing.T) { ...@@ -39,7 +41,7 @@ func TestDecode(t *testing.T) {
t.Errorf("parsing %q: %v", f[0], err) t.Errorf("parsing %q: %v", f[0], err)
continue continue
} }
syntax, asm := f[1], f[2] asm := f[1]
inst, decodeErr := Decode(code) inst, decodeErr := Decode(code)
if decodeErr != nil && decodeErr != errUnknown { if decodeErr != nil && decodeErr != errUnknown {
// Some rarely used system instructions are not supported // Some rarely used system instructions are not supported
...@@ -71,8 +73,16 @@ func TestDecode(t *testing.T) { ...@@ -71,8 +73,16 @@ func TestDecode(t *testing.T) {
if strings.Replace(out, " ", "", -1) != strings.Replace(asm, " ", "", -1) && !hasPrefix(asm, Todo...) { if strings.Replace(out, " ", "", -1) != strings.Replace(asm, " ", "", -1) && !hasPrefix(asm, Todo...) {
// Exclude MSR since GNU objdump result is incorrect. eg. 0xd504431f msr s0_4_c4_c3_0, xzr // Exclude MSR since GNU objdump result is incorrect. eg. 0xd504431f msr s0_4_c4_c3_0, xzr
if !strings.HasSuffix(asm, " nv") && !strings.HasPrefix(asm, "msr") { if !strings.HasSuffix(asm, " nv") && !strings.HasPrefix(asm, "msr") {
t.Errorf("Decode(%s) [%s] = %s, want %s", f[0], syntax, out, asm) t.Errorf("Decode(%s) [%s] = %s, want %s", strings.Trim(f[0], "|"), syntax, out, asm)
} }
} }
} }
} }
func TestDecodeGNUSyntax(t *testing.T) {
testDecode(t, "gnu")
}
func TestDecodeGoSyntax(t *testing.T) {
testDecode(t, "plan9")
}
...@@ -14,11 +14,13 @@ import ( ...@@ -14,11 +14,13 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
...@@ -220,7 +222,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, ...@@ -220,7 +222,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name() file = f.Name()
f.Seek(start, 0) f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f) w := bufio.NewWriter(f)
defer w.Flush() defer w.Flush()
size = 0 size = 0
...@@ -565,9 +567,10 @@ func hexCases(t *testing.T, encoded string) func(func([]byte)) { ...@@ -565,9 +567,10 @@ func hexCases(t *testing.T, encoded string) func(func([]byte)) {
// testdataCases generates the test cases recorded in testdata/cases.txt. // testdataCases generates the test cases recorded in testdata/cases.txt.
// It only uses the inputs; it ignores the answers recorded in that file. // It only uses the inputs; it ignores the answers recorded in that file.
func testdataCases(t *testing.T) func(func([]byte)) { func testdataCases(t *testing.T, syntax string) func(func([]byte)) {
var codes [][]byte var codes [][]byte
data, err := ioutil.ReadFile("testdata/cases.txt") input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -536,8 +536,13 @@ type MemExtend struct { ...@@ -536,8 +536,13 @@ type MemExtend struct {
Base RegSP Base RegSP
Index Reg Index Reg
Extend ExtShift Extend ExtShift
// Amount indicates the index shift amount (but also see ShiftMustBeZero field below).
Amount uint8 Amount uint8
Absent bool // ShiftMustBeZero is set to true when the shift amount must be 0, even if the
// Amount field is not 0. In GNU syntax, a #0 shift amount is printed if Amount
// is not 0 but ShiftMustBeZero is true; #0 is not printed if Amount is 0 and
// ShiftMustBeZero is true. Both cases represent shift by 0 bit.
ShiftMustBeZero bool
} }
func (MemExtend) isArg() {} func (MemExtend) isArg() {}
...@@ -545,7 +550,7 @@ func (MemExtend) isArg() {} ...@@ -545,7 +550,7 @@ func (MemExtend) isArg() {}
func (m MemExtend) String() string { func (m MemExtend) String() string {
Rbase := m.Base.String() Rbase := m.Base.String()
RIndex := m.Index.String() RIndex := m.Index.String()
if m.Absent { if m.ShiftMustBeZero {
if m.Amount != 0 { if m.Amount != 0 {
return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String()) return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String())
} else { } else {
......
...@@ -9,7 +9,12 @@ import ( ...@@ -9,7 +9,12 @@ import (
"testing" "testing"
) )
func TestObjdumpARM64Testdata(t *testing.T) { testObjdumpARM64(t, testdataCases(t)) } func TestObjdumpARM64TestDecodeGNUSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "gnu"))
}
func TestObjdumpARM64TestDecodeGoSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "plan9"))
}
func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) } func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) }
func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) } func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) }
func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) } func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) }
......
...@@ -232,7 +232,7 @@ func parseContinuation(line []byte, enc []byte) []byte { ...@@ -232,7 +232,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// writeELF64 writes an ELF64 header to the file, describing a text // writeELF64 writes an ELF64 header to the file, describing a text
// segment that starts at start (0x8000) and extends for size bytes. // segment that starts at start (0x8000) and extends for size bytes.
func writeELF64(f *os.File, size int) error { func writeELF64(f *os.File, size int) error {
f.Seek(0, 0) f.Seek(0, io.SeekStart)
var hdr elf.Header64 var hdr elf.Header64
var prog elf.Prog64 var prog elf.Prog64
var sect elf.Section64 var sect elf.Section64
......
...@@ -53,7 +53,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -53,7 +53,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// Move addressing mode into opcode suffix. // Move addressing mode into opcode suffix.
suffix := "" suffix := ""
switch inst.Op { switch inst.Op {
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1: case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1, ST1:
switch mem := inst.Args[1].(type) { switch mem := inst.Args[1].(type) {
case MemImmediate: case MemImmediate:
switch mem.Mode { switch mem.Mode {
...@@ -114,6 +114,8 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -114,6 +114,8 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
rno = int(a) rno = int(a)
case RegisterWithArrangementAndIndex: case RegisterWithArrangementAndIndex:
op = "VMOV" op = "VMOV"
case RegisterWithArrangement:
op = "VMOV"
} }
if rno >= 0 && rno <= int(WZR) { if rno >= 0 && rno <= int(WZR) {
op = "MOVW" op = "MOVW"
...@@ -133,6 +135,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -133,6 +135,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} }
if rno <= uint16(WZR) { if rno <= uint16(WZR) {
op = "MOVWU" + suffix op = "MOVWU" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else { } else {
op = "MOVD" + suffix op = "MOVD" + suffix
} }
...@@ -173,6 +181,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -173,6 +181,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} }
if rno <= uint16(WZR) { if rno <= uint16(WZR) {
op = "MOVW" + suffix op = "MOVW" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else { } else {
op = "MOVD" + suffix op = "MOVD" + suffix
} }
...@@ -230,6 +244,15 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -230,6 +244,15 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} }
args[1], args[2], args[3] = args[3], args[1], args[2] args[1], args[2], args[3] = args[3], args[1], args[2]
case LDAXP, LDXP:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
fallthrough
case STP, LDP: case STP, LDP:
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1]) args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
args[1] = args[2] args[1] = args[2]
...@@ -239,7 +262,20 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -239,7 +262,20 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} else if op == "LDP" { } else if op == "LDP" {
op = op + suffix op = op + suffix
return op + " " + args[1] + ", " + args[0] return op + " " + args[1] + ", " + args[0]
} else if op == "LDAXP" || op == "LDXP" || op == "LDAXPW" || op == "LDXPW" {
return op + " " + args[1] + ", " + args[0]
}
case STLXP, STXP:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
} }
args[1] = fmt.Sprintf("(%s, %s)", args[1], args[2])
args[2] = args[3]
return op + " " + args[1] + ", " + args[2] + ", " + args[0]
case FCCMP, FCCMPE: case FCCMP, FCCMPE:
args[0], args[1] = args[1], args[0] args[0], args[1] = args[1], args[0]
...@@ -251,7 +287,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -251,7 +287,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} }
fallthrough fallthrough
case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL: case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL, FMADD, FMSUB, FNMADD, FNMSUB:
if strings.HasSuffix(op, "MADD") || strings.HasSuffix(op, "MSUB") {
args[2], args[3] = args[3], args[2]
}
if r, ok := inst.Args[0].(Reg); ok { if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r) rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) { if rno >= uint16(S0) && rno <= uint16(S31) {
...@@ -337,6 +376,19 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -337,6 +376,19 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
addr := int64(inst.Args[1].(PCRel)) addr := int64(inst.Args[1].(PCRel))
args[1] = fmt.Sprintf("%d(PC)", addr) args[1] = fmt.Sprintf("%d(PC)", addr)
case MSR:
args[0] = inst.Args[0].String()
case ST1:
op = fmt.Sprintf("V%s", op) + suffix
args[0], args[1] = args[1], args[0]
case LD1:
op = fmt.Sprintf("V%s", op) + suffix
case UMOV:
op = "VMOV"
default: default:
index := sort.SearchStrings(noSuffixOpSet, op) index := sort.SearchStrings(noSuffixOpSet, op)
if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) { if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
...@@ -350,6 +402,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -350,6 +402,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
op = fmt.Sprintf("V%s", op) op = fmt.Sprintf("V%s", op)
} }
if rno >= int(B0) && rno <= int(Q31) && !strings.HasPrefix(op, "F") {
op = fmt.Sprintf("V%s", op)
}
if rno >= 0 && rno <= int(WZR) { if rno >= 0 && rno <= int(WZR) {
// Add "w" to opcode suffix. // Add "w" to opcode suffix.
op += "W" op += "W"
...@@ -381,6 +436,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text ...@@ -381,6 +436,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// No need add "W" to opcode suffix. // No need add "W" to opcode suffix.
// Opcode must be inserted in ascending order. // Opcode must be inserted in ascending order.
var noSuffixOpSet = strings.Fields(` var noSuffixOpSet = strings.Fields(`
AESD
AESE
AESIMC
AESMC
CRC32B CRC32B
CRC32CB CRC32CB
CRC32CH CRC32CH
...@@ -393,8 +452,19 @@ LDARB ...@@ -393,8 +452,19 @@ LDARB
LDARH LDARH
LDAXRB LDAXRB
LDAXRH LDAXRH
LDTRH
LDXRB LDXRB
LDXRH LDXRH
SHA1C
SHA1H
SHA1M
SHA1P
SHA1SU0
SHA1SU1
SHA256H
SHA256H2
SHA256SU0
SHA256SU1
`) `)
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
...@@ -423,9 +493,14 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -423,9 +493,14 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
regno := uint16(a) & 31 regno := uint16(a) & 31
if regenum >= uint16(B0) && regenum <= uint16(D31) { if regenum >= uint16(B0) && regenum <= uint16(D31) {
if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") {
// FP registers are the same ones as SIMD registers // FP registers are the same ones as SIMD registers
// Print Fn for scalar variant to align with assembler (e.g., FCVT) // Print Fn for scalar variant to align with assembler (e.g., FCVT, SCVTF, UCVTF, etc.)
return fmt.Sprintf("F%d", regno) return fmt.Sprintf("F%d", regno)
} else {
return fmt.Sprintf("V%d", regno)
}
} else if regenum >= uint16(Q0) && regenum <= uint16(Q31) { } else if regenum >= uint16(Q0) && regenum <= uint16(Q31) {
// Print Vn to align with assembler (e.g., SHA256H) // Print Vn to align with assembler (e.g., SHA256H)
return fmt.Sprintf("V%d", regno) return fmt.Sprintf("V%d", regno)
...@@ -503,7 +578,6 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -503,7 +578,6 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
case MemExtend: case MemExtend:
base := "" base := ""
index := "" index := ""
extend := ""
indexreg := "" indexreg := ""
regno := uint16(a.Base) & 31 regno := uint16(a.Base) & 31
if regno == 31 { if regno == 31 {
...@@ -517,15 +591,28 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -517,15 +591,28 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
} else { } else {
indexreg = fmt.Sprintf("R%d", regno) indexreg = fmt.Sprintf("R%d", regno)
} }
if a.Extend == lsl { if a.Extend == lsl {
if a.Amount != 0 { // a.Amount indicates the index shift amount, encoded in "S" field.
extend = fmt.Sprintf("<<%d", a.Amount) // a.ShiftMustBeZero is set true when the index shift amount must be 0,
// even if the a.Amount field is not 0.
// When a.ShiftMustBeZero is ture, GNU syntax prints #0 shift amount if
// "S" equals to 1, or does not print #0 shift amount if "S" equals to 0.
// Go syntax should never print a zero index shift amount.
if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
} else {
index = fmt.Sprintf("(%s)", indexreg)
} }
} else { } else {
extend = "unimplemented!" if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
} else {
index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
}
} }
index = indexreg + extend
return index + base return base + index
case Cond: case Cond:
switch arg.String() { switch arg.String() {
...@@ -592,7 +679,7 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -592,7 +679,7 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
result := a.r.String() result := a.r.String()
arrange := a.a.String() arrange := a.a.String()
result += arrange result += arrange
if a.cnt > 0 { if a.cnt > 1 {
result = "[" + result result = "[" + result
for i := 1; i < int(a.cnt); i++ { for i := 1; i < int(a.cnt); i++ {
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31) cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
...@@ -605,6 +692,10 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg ...@@ -605,6 +692,10 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
case Systemreg: case Systemreg:
return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7) return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
case Imm_prfop:
if strings.Contains(a.String(), "#") {
return fmt.Sprintf("$%d", a)
}
} }
return strings.ToUpper(arg.String()) return strings.ToUpper(arg.String())
......
go test command: go test command:
cd ..; go test -run 'ObjdumpARM64Cond' -v -timeout 10h -long 2>&1 | tee log cd ..; go test -run 'ObjdumpARM64Cond' -v -timeout 10h -long 2>&1 | tee log
cd ..; go test -run 'ObjdumpARM64Testdata' -v -timeout 10h -long 2>&1 | tee -a log cd ..; go test -run 'ObjdumpARM64TestGUNSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64TestGoSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64' -v -timeout 10h -long 2>&1 | tee -a log cd ..; go test -run 'ObjdumpARM64' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64Manual' -v -timeout 10h -long 2>&1 | tee -a log cd ..; go test -run 'ObjdumpARM64Manual' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'TestDecode' cd ..; go test -run 'TestDecodeGNUSyntax'
cd ..; go test -run 'TestDecodeGoSyntax'
cd ..; go test -run '.*' cd ..; go test -run '.*'
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"encoding/hex" "encoding/hex"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
...@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, ...@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name() file = f.Name()
f.Seek(start, 0) f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f) w := bufio.NewWriter(f)
defer w.Flush() defer w.Flush()
size = 0 size = 0
......
...@@ -188,7 +188,7 @@ func parseContinuation(line []byte, enc []byte) []byte { ...@@ -188,7 +188,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start // describing a text segment that starts at start
// and extends for size bytes. // and extends for size bytes.
func writeELF64(f *os.File, size int) error { func writeELF64(f *os.File, size int) error {
f.Seek(0, 0) f.Seek(0, io.SeekStart)
var hdr elf.Header64 var hdr elf.Header64
var prog elf.Prog64 var prog elf.Prog64
var sect elf.Section64 var sect elf.Section64
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"encoding/hex" "encoding/hex"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
...@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, ...@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name() file = f.Name()
f.Seek(start, 0) f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f) w := bufio.NewWriter(f)
defer w.Flush() defer w.Flush()
size = 0 size = 0
......
...@@ -176,7 +176,7 @@ func parseContinuation(line []byte, enc []byte) []byte { ...@@ -176,7 +176,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start // describing a text segment that starts at start
// and extends for size bytes. // and extends for size bytes.
func writeELF32(f *os.File, size int) error { func writeELF32(f *os.File, size int) error {
f.Seek(0, 0) f.Seek(0, io.SeekStart)
var hdr elf.Header32 var hdr elf.Header32
var prog elf.Prog32 var prog elf.Prog32
var sect elf.Section32 var sect elf.Section32
...@@ -246,7 +246,7 @@ func writeELF32(f *os.File, size int) error { ...@@ -246,7 +246,7 @@ func writeELF32(f *os.File, size int) error {
// describing a text segment that starts at start // describing a text segment that starts at start
// and extends for size bytes. // and extends for size bytes.
func writeELF64(f *os.File, size int) error { func writeELF64(f *os.File, size int) error {
f.Seek(0, 0) f.Seek(0, io.SeekStart)
var hdr elf.Header64 var hdr elf.Header64
var prog elf.Prog64 var prog elf.Prog64
var sect elf.Section64 var sect elf.Section64
......
...@@ -15,26 +15,26 @@ ...@@ -15,26 +15,26 @@
{ {
"canonical": "golang.org/x/arch/x86/x86asm", "canonical": "golang.org/x/arch/x86/x86asm",
"local": "golang.org/x/arch/x86/x86asm", "local": "golang.org/x/arch/x86/x86asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2", "revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2017-12-26T02:13:20Z" "revisionTime": "2018-04-06T10:28:20Z"
}, },
{ {
"canonical": "golang.org/x/arch/arm/armasm", "canonical": "golang.org/x/arch/arm/armasm",
"local": "golang.org/x/arch/arm/armasm", "local": "golang.org/x/arch/arm/armasm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2", "revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2017-12-26T02:13:20Z" "revisionTime": "2018-04-06T10:28:20Z"
}, },
{ {
"canonical": "golang.org/x/arch/ppc64/ppc64asm", "canonical": "golang.org/x/arch/ppc64/ppc64asm",
"local": "golang.org/x/arch/ppc64/ppc64asm", "local": "golang.org/x/arch/ppc64/ppc64asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2", "revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2017-12-26T02:13:20Z" "revisionTime": "2018-04-06T10:28:20Z"
}, },
{ {
"canonical": "golang.org/x/arch/arm64/arm6464asm", "canonical": "golang.org/x/arch/arm64/arm6464asm",
"local": "golang.org/x/arch/arm64/arm64asm", "local": "golang.org/x/arch/arm64/arm64asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2", "revision": "9111c30535f37e70dcaf5956d34b03233f90f3b6",
"revisionTime": "2017-12-26T02:13:20Z" "revisionTime": "2018-03-13T04:07:09Z"
} }
] ]
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment