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