diff --git a/internal/gen/loadertest.go b/internal/gen/loadertest.go index 55d267d..078a6ba 100644 --- a/internal/gen/loadertest.go +++ b/internal/gen/loadertest.go @@ -9,12 +9,21 @@ import ( "github.com/mmcloughlin/avo/internal/inst" ) -type LoaderTest struct{} +type LoaderTest struct { + sym string // reference to the test function symbol + rel8 string // label to be used for near jumps + rel32 string // label for far jumps +} -func (l LoaderTest) Generate(w io.Writer, is []*inst.Instruction) error { +func (l *LoaderTest) Generate(w io.Writer, is []*inst.Instruction) error { p := &printer{w: w} - p.printf("TEXT loadertest(SB), 0, $0\n") + l.sym = "\u00b7loadertest(SB)" + p.printf("TEXT %s, 0, $0\n", l.sym) + + // Define a label for far jumps. + p.printf("rel32:\n") + l.rel32 = "rel32" counts := map[string]int{} @@ -26,8 +35,14 @@ func (l LoaderTest) Generate(w io.Writer, is []*inst.Instruction) error { continue } + if i.Opcode[0] == 'J' { + label := fmt.Sprintf("rel8_%s", strings.ToLower(i.Opcode)) + p.printf("%s:\n", label) + l.rel8 = label + } + for _, f := range i.Forms { - as := args(f.Operands) + as := l.args(i.Opcode, f.Operands) p.printf("\t// %#v\n", f.Operands) if as == nil { p.printf("\t// TODO\n") @@ -53,6 +68,7 @@ func (l LoaderTest) skip(opcode string) (bool, string) { prefixes := map[string]string{ "PUSH": "PUSH can produce 'unbalanced PUSH/POP' assembler error", "POP": "POP can produce 'unbalanced PUSH/POP' assembler error", + "CALL": "handled specially", } for p, m := range prefixes { if strings.HasPrefix(opcode, p) { @@ -62,10 +78,15 @@ func (l LoaderTest) skip(opcode string) (bool, string) { return false, "" } -func args(ops []inst.Operand) []string { +func (l LoaderTest) args(opcode string, ops []inst.Operand) []string { + // Special case for CALL, since it needs a different type of rel32 argument than others. + if opcode == "CALL" { + return []string{l.sym} + } + as := make([]string, len(ops)) for i, op := range ops { - a := arg(op.Type) + a := l.arg(op.Type) if a == "" { return nil } @@ -75,7 +96,7 @@ func args(ops []inst.Operand) []string { } // arg generates an argument for an operand of the given type. -func arg(t string) string { +func (l LoaderTest) arg(t string) string { m := map[string]string{ "1": "$1", // "3": "$3", // @@ -145,8 +166,8 @@ func arg(t string) string { // // // - // - // + "rel8": l.rel8, // + "rel32": l.rel32, // // // diff --git a/internal/load/load.go b/internal/load/load.go index d456a95..95a6b12 100644 --- a/internal/load/load.go +++ b/internal/load/load.go @@ -134,7 +134,17 @@ func (l Loader) include(f opcodesxml.Form) bool { // Some specific exclusions. switch f.GASName { - case "callq": + // Certain branch instructions appear to not be supported. + // + // Reference: https://github.com/golang/go/blob/649b89377e91ad6dbe710784f9e662082d31a1ff/src/cmd/asm/internal/asm/testdata/amd64enc.s#L757 + // + // //TODO: CALLQ* (BX) // ff13 + // + // Reference: https://github.com/golang/go/blob/649b89377e91ad6dbe710784f9e662082d31a1ff/src/cmd/asm/internal/asm/testdata/amd64enc.s#L2108 + // + // //TODO: LJMPL* (R11) // 41ff2b + // + case "callq", "jmpl": return false } diff --git a/internal/opcodescsv/analysis.go b/internal/opcodescsv/analysis.go index 3a78dd4..918c26b 100644 --- a/internal/opcodescsv/analysis.go +++ b/internal/opcodescsv/analysis.go @@ -103,7 +103,7 @@ func order(i *x86csv.Inst) OperandOrder { // skip decides whether to ignore the instruction for analysis purposes. func skip(i *x86csv.Inst) bool { switch { - case strings.Contains(i.GoOpcode(), "/"): + case strings.ContainsAny(i.GoOpcode(), "/*"): return true case i.Mode64 == "I": // Invalid in 64-bit mode. return true