Files

116 lines
2.5 KiB
Go
Raw Permalink Normal View History

2018-11-21 13:02:18 -06:00
package opcodescsv
import (
2018-11-21 23:06:29 -06:00
"reflect"
2018-11-21 13:02:18 -06:00
"strconv"
"strings"
"golang.org/x/arch/x86/x86csv"
)
// Alias records another possible name for an instruction configuration.
2018-11-21 13:02:18 -06:00
type Alias struct {
2018-11-21 22:28:55 -06:00
Opcode string
DataSize int
NumOperands int
2018-11-21 13:02:18 -06:00
}
// BuildAliasMap constructs a map from AT&T/GNU/Intel to Go syntax.
func BuildAliasMap(is []*x86csv.Inst) (map[Alias]string, error) {
m := map[Alias]string{}
for _, i := range is {
2018-11-22 14:12:20 -06:00
if skip(i) {
continue
}
2018-11-21 23:06:29 -06:00
s, err := strconv.Atoi("0" + i.DataSize)
2018-11-21 13:02:18 -06:00
if err != nil {
return nil, err
}
for _, alt := range []string{i.IntelOpcode(), i.GNUOpcode()} {
if strings.ToUpper(alt) != i.GoOpcode() {
2018-11-21 22:28:55 -06:00
a := Alias{
Opcode: strings.ToLower(alt),
DataSize: s,
NumOperands: len(i.GoArgs()),
}
m[a] = i.GoOpcode()
2018-11-21 13:02:18 -06:00
}
}
}
return m, nil
}
// OperandOrder describes the order an instruction takes its operands.
2018-11-22 14:12:20 -06:00
type OperandOrder uint8
// Possible operand orders.
2018-11-22 14:12:20 -06:00
const (
UnknownOrder = iota
IntelOrder
ReverseIntelOrder
CMP3Order
)
// BuildOrderMap collects operand order information from the instruction list.
func BuildOrderMap(is []*x86csv.Inst) map[string]OperandOrder {
s := map[string]OperandOrder{}
2018-11-21 23:06:29 -06:00
for _, i := range is {
2018-11-22 14:12:20 -06:00
if skip(i) {
continue
2018-11-21 23:06:29 -06:00
}
2018-11-22 14:12:20 -06:00
s[i.GoOpcode()] = order(i)
2018-11-21 13:02:18 -06:00
}
2018-11-21 23:06:29 -06:00
return s
2018-11-21 13:02:18 -06:00
}
2018-11-22 14:12:20 -06:00
// order categorizes the operand order of an instruction.
func order(i *x86csv.Inst) OperandOrder {
// Is it Intel order already?
intel := i.IntelArgs()
if reflect.DeepEqual(i.GoArgs(), intel) {
return IntelOrder
}
// Check if it's reverse Intel.
for l, r := 0, len(intel)-1; l < r; l, r = l+1, r-1 {
intel[l], intel[r] = intel[r], intel[l]
}
if reflect.DeepEqual(i.GoArgs(), intel) {
return ReverseIntelOrder
}
// Otherwise we could be in the bizarre special-case of 3-argument CMP instructions.
//
// Reference: https://github.com/golang/arch/blob/b19384d3c130858bb31a343ea8fce26be71b5998/x86/x86spec/format.go#L138-L144
//
// case "CMPPD", "CMPPS", "CMPSD", "CMPSS":
// // rotate destination to end but don't swap comparison operands
// if len(args) == 3 {
// args[0], args[1], args[2] = args[2], args[0], args[1]
// break
// }
// fallthrough
//
switch i.GoOpcode() {
case "CMPPD", "CMPPS", "CMPSD", "CMPSS":
if len(i.GoArgs()) == 3 {
return CMP3Order
}
}
return UnknownOrder
}
// skip decides whether to ignore the instruction for analysis purposes.
func skip(i *x86csv.Inst) bool {
switch {
2018-11-22 16:21:05 -06:00
case strings.ContainsAny(i.GoOpcode(), "/*"):
2018-11-22 14:12:20 -06:00
return true
case i.Mode64 == "I": // Invalid in 64-bit mode.
return true
}
return false
}