forked from vmware-archive/vmw-guestinfo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Assembly is tricky, it should be generated. This change adds an avo-based generator that handles the common parts and subtle differences of our 386 vs amd64 implementations. asm/ is its own module so that we don't add avo dependencies to vmw-guestinfo module, and its downstream consumers.
- Loading branch information
1 parent
560fab2
commit 1edadea
Showing
12 changed files
with
368 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2020 Google, Inc. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package asm | ||
|
||
import ( | ||
"flag" | ||
"go/types" | ||
"log" | ||
"os" | ||
|
||
"github.com/mmcloughlin/avo/build" | ||
"github.com/mmcloughlin/avo/gotypes" | ||
"github.com/mmcloughlin/avo/ir" | ||
) | ||
|
||
// CLI utilities for ASM generator | ||
|
||
// AvoContext is an extended context for Avo that conveys information about | ||
// the target architecture. In particular this allows some level of | ||
// abstraction over registers. | ||
type AvoContext struct { | ||
*build.Context | ||
Arch string | ||
} | ||
|
||
// Missing instructions from avo. | ||
|
||
// INL is the INL instruction. | ||
func (ctx *AvoContext) INL() { | ||
ctx.Instruction(&ir.Instruction{Opcode: "INL"}) | ||
} | ||
|
||
// INSB is the INSB instruction. | ||
func (ctx *AvoContext) INSB() { | ||
ctx.Instruction(&ir.Instruction{Opcode: "INSB"}) | ||
} | ||
|
||
// OUTSB is the OUTSB instruction. | ||
func (ctx *AvoContext) OUTSB() { | ||
ctx.Instruction(&ir.Instruction{Opcode: "OUTSB"}) | ||
} | ||
|
||
// REP is the REP instruction. | ||
func (ctx *AvoContext) REP() { | ||
ctx.Instruction(&ir.Instruction{Opcode: "REP"}) | ||
} | ||
|
||
// AvoMainFunc is the type of functions that can be used with GenAsm. | ||
type AvoMainFunc func(ctx *AvoContext) error | ||
|
||
// GenAsm is our main entry point for ASM code generation. | ||
// It augments avo flags with a "-arch", the content of which is | ||
// exposed in AvoContext. That value also drives the alignments in | ||
// the generated code. | ||
func GenAsm(f AvoMainFunc) { | ||
var arch string | ||
|
||
// reset the flagset to allow NewFlags to work. | ||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) | ||
var flags = build.NewFlags(flag.CommandLine) | ||
flag.CommandLine.StringVar(&arch, "arch", "amd64", "arch to use") | ||
|
||
flag.Parse() | ||
|
||
// This is needed to get proper alignment of the return values. | ||
// amd64 is the global default in avo, but not modifying it might | ||
// result in misalignment of the stack. | ||
gotypes.Sizes = types.SizesFor("gc", arch) | ||
|
||
cfg := flags.Config() | ||
|
||
ctx := &AvoContext{ | ||
Context: build.NewContext(), | ||
Arch: arch, | ||
} | ||
|
||
if err := f(ctx); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
os.Exit(build.Main(cfg, ctx.Context)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/vmware/vmw-guestinfo/asm | ||
|
||
go 1.12 | ||
|
||
require github.com/mmcloughlin/avo v0.0.0-20200201205037-fb157e1de836 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/mmcloughlin/avo v0.0.0-20200201205037-fb157e1de836 h1:knhFIJojRvDc83PlhHV2u9hn1co3QEwZ6ZHwle3KtHs= | ||
github.com/mmcloughlin/avo v0.0.0-20200201205037-fb157e1de836/go.mod h1:L0u9qfRMLNBO97u6pPukRp6ncoQz0Q25W69fvtht3vA= | ||
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e h1:nOOVVcLC+/3MeovP40q5lCiWmP1Z1DaN8yn8ngU63hw= | ||
golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Copyright 2016-2017 VMware, Inc. All Rights Reserved. | ||
// Copyright 2020 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// +build ignore | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
. "github.com/mmcloughlin/avo/build" | ||
"github.com/mmcloughlin/avo/reg" | ||
|
||
"github.com/vmware/vmw-guestinfo/asm" | ||
) | ||
|
||
// Doc of the golang plan9 assembler | ||
// http://p9.nyx.link/labs/sys/doc/asm.html | ||
// | ||
// A good primer of how to write golang with some plan9 flavored assembly | ||
// http://www.doxsey.net/blog/go-and-assembly | ||
// | ||
// Some x86 references | ||
// http://www.eecg.toronto.edu/~amza/www.mindsec.com/files/x86regs.html | ||
// https://cseweb.ucsd.edu/classes/sp10/cse141/pdf/02/S01_x86_64.key.pdf | ||
// https://en.wikibooks.org/wiki/X86_Assembly/Other_Instructions | ||
// | ||
// (This one is invaluable. Has a working example of how a standard function | ||
// call looks on the stack with the associated assembly.) | ||
// https://www.recurse.com/blog/7-understanding-c-by-learning-assembly | ||
// | ||
// Reference with raw form of the Opcode | ||
// http://x86.renejeschke.de/html/file_module_x86_id_139.html | ||
// | ||
// Massive x86_64 reference | ||
// http://ref.x86asm.net/coder64.html#xED | ||
|
||
type config struct { | ||
wordSize uint8 | ||
registers map[string]reg.Register | ||
} | ||
|
||
func setup(ctx *asm.AvoContext) (*config, error) { | ||
switch ctx.Arch { | ||
case "amd64": | ||
return &config{ | ||
wordSize: 64, | ||
registers: map[string]reg.Register{ | ||
"ax": reg.RAX, | ||
"bx": reg.RBX, | ||
"cx": reg.RCX, | ||
"dx": reg.RDX, | ||
"si": reg.RSI, | ||
"di": reg.RDI, | ||
"bp": reg.RBP, | ||
}, | ||
}, nil | ||
case "386": | ||
return &config{ | ||
wordSize: 32, | ||
registers: map[string]reg.Register{ | ||
"ax": reg.EAX, | ||
"bx": reg.EBX, | ||
"cx": reg.ECX, | ||
"dx": reg.EDX, | ||
"si": reg.ESI, | ||
"di": reg.EDI, | ||
"bp": reg.EBP, | ||
}, | ||
}, nil | ||
default: | ||
return nil, fmt.Errorf("unsupported architecture: %s", ctx.Arch) | ||
} | ||
} | ||
|
||
func code(ctx *asm.AvoContext) error { | ||
cfg, err := setup(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// for all the following functions, we use those 7 registers as both | ||
// input and output. | ||
regs := []string{"ax", "bx", "cx", "dx", "si", "di", "bp"} | ||
|
||
funcs := []struct { | ||
name string | ||
body func() | ||
}{ | ||
{"bdoor_inout", func() { | ||
ctx.Comment("IN to DX from AX") | ||
ctx.INL() | ||
}}, | ||
{"bdoor_hbout", func() { | ||
ctx.CLD() | ||
ctx.REP() | ||
ctx.OUTSB() | ||
}}, | ||
{"bdoor_hbin", func() { | ||
ctx.CLD() | ||
ctx.REP() | ||
ctx.INSB() | ||
}}, | ||
{"bdoor_inout_test", func() {}}, | ||
} | ||
|
||
for _, f := range funcs { | ||
// generate function signature. By convention we use: | ||
// - $REG as input | ||
// - and ret$REG as output. | ||
proto := fmt.Sprintf( | ||
"func(%s uint%d) (%s uint%d)", | ||
strings.Join(regs, ","), | ||
cfg.wordSize, | ||
"ret"+strings.Join(regs, ",ret"), | ||
cfg.wordSize, | ||
) | ||
|
||
ctx.Function(f.name) | ||
ctx.Attributes(NOSPLIT | WRAPPER) | ||
ctx.SignatureExpr(proto) | ||
|
||
// load all registers | ||
for _, r := range regs { | ||
ctx.Load(ctx.Param(r), cfg.registers[r]) | ||
} | ||
|
||
// execute backdoor function | ||
f.body() | ||
|
||
// store all registers | ||
for _, r := range regs { | ||
ctx.Store(cfg.registers[r], ctx.Return("ret"+r)) | ||
} | ||
|
||
ctx.RET() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
asm.GenAsm(code) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.