examples/sha1: single block

This commit is contained in:
Michael McLoughlin
2018-12-21 00:30:59 -08:00
parent 224cccd2b1
commit f464082484
8 changed files with 1525 additions and 11 deletions

19
ast.go
View File

@@ -10,15 +10,6 @@ type Asm interface {
Asm() string
}
// GoType represents a Golang type.
type GoType interface{}
// Parameter represents a parameter to an assembly function.
type Parameter struct {
Name string
Type GoType
}
type Operand interface {
Asm
}
@@ -112,6 +103,7 @@ func NewFile() *File {
type Function struct {
Name string
Signature *gotypes.Signature
LocalSize int
Nodes []Node
@@ -133,6 +125,12 @@ func (f *Function) SetSignature(s *gotypes.Signature) {
f.Signature = s
}
func (f *Function) AllocLocal(size int) operand.Mem {
ptr := operand.NewStackAddr(f.LocalSize)
f.LocalSize += size
return ptr
}
func (f *Function) AddInstruction(i *Instruction) {
f.AddNode(i)
}
@@ -164,8 +162,7 @@ func (f *Function) Stub() string {
// FrameBytes returns the size of the stack frame in bytes.
func (f *Function) FrameBytes() int {
// TODO(mbm): implement Function.FrameBytes()
return 0
return f.LocalSize
}
// ArgumentBytes returns the size of the arguments in bytes.

View File

@@ -6,6 +6,7 @@ import (
"github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/gotypes"
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
"golang.org/x/tools/go/packages"
)
@@ -69,6 +70,10 @@ func (c *Context) types() *types.Package {
return c.pkg.Types
}
func (c *Context) AllocLocal(size int) operand.Mem {
return c.activefunc().AllocLocal(size)
}
func (c *Context) Instruction(i *avo.Instruction) {
c.activefunc().AddNode(i)
}

View File

@@ -5,6 +5,7 @@ import (
"os"
"github.com/mmcloughlin/avo/gotypes"
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
@@ -47,3 +48,5 @@ func ReturnIndex(i int) gotypes.Component { return ctx.ReturnIndex(i) }
func Load(src gotypes.Component, dst reg.Register) reg.Register { return ctx.Load(src, dst) }
func Store(src reg.Register, dst gotypes.Component) { ctx.Store(src, dst) }
func AllocLocal(size int) operand.Mem { return ctx.AllocLocal(size) }

124
examples/sha1/asm.go Normal file
View File

@@ -0,0 +1,124 @@
// +build ignore
package main
import (
. "github.com/mmcloughlin/avo/build"
. "github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
)
func main() {
TEXT("block", "func(h *[5]uint32, m []byte)")
h := Mem{Base: Load(Param("h"), GP64v())}
m := Mem{Base: Load(Param("m").Base(), GP64v())}
// Store message values on the stack.
w := AllocLocal(64)
W := func(r int) Mem { return w.Idx((r % 16) * 4) }
// Load initial hash.
h0, h1, h2, h3, h4 := GP32v(), GP32v(), GP32v(), GP32v(), GP32v()
MOVL(h.Idx(0), h0)
MOVL(h.Idx(4), h1)
MOVL(h.Idx(8), h2)
MOVL(h.Idx(12), h3)
MOVL(h.Idx(16), h4)
// Initialize registers.
a, b, c, d, e := GP32v(), GP32v(), GP32v(), GP32v(), GP32v()
MOVL(h0, a)
MOVL(h1, b)
MOVL(h2, c)
MOVL(h3, d)
MOVL(h4, e)
// Generate round updates.
quarter := []struct {
F func(reg.Register, reg.Register, reg.Register) reg.Register
K uint32
}{
{choose, 0x5a827999},
{xor, 0x6ed9eba1},
{majority, 0x8f1bbcdc},
{xor, 0xca62c1d6},
}
for r := 0; r < 80; r++ {
q := quarter[r/20]
// Load message value.
u := GP32v()
if r < 16 {
MOVL(m.Idx(4*r), u)
BSWAPL(u)
} else {
MOVL(W(r-3), u)
XORL(W(r-8), u)
XORL(W(r-14), u)
XORL(W(r-16), u)
ROLL(Imm(1), u)
}
MOVL(u, W(r))
// Compute the next state register.
t := GP32v()
MOVL(a, t)
ROLL(Imm(5), t)
ADDL(q.F(b, c, d), t)
ADDL(e, t)
ADDL(Imm(q.K), t)
ADDL(u, t)
// Update registers.
ROLL(Imm(30), b)
a, b, c, d, e = t, a, b, c, d
}
// Final add.
ADDL(a, h0)
ADDL(b, h1)
ADDL(c, h2)
ADDL(d, h3)
ADDL(e, h4)
// Store results back.
MOVL(h0, h.Idx(0))
MOVL(h1, h.Idx(4))
MOVL(h2, h.Idx(8))
MOVL(h3, h.Idx(12))
MOVL(h4, h.Idx(16))
RET()
Generate()
}
func choose(b, c, d reg.Register) reg.Register {
r := GP32v()
MOVL(d, r)
XORL(c, r)
ANDL(b, r)
XORL(d, r)
return r
}
func xor(b, c, d reg.Register) reg.Register {
r := GP32v()
MOVL(b, r)
XORL(c, r)
XORL(d, r)
return r
}
func majority(b, c, d reg.Register) reg.Register {
t, r := GP32v(), GP32v()
MOVL(b, t)
ORL(c, t)
ANDL(d, t)
MOVL(b, r)
ANDL(c, r)
ORL(t, r)
return r
}

1341
examples/sha1/sha1.s Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
package sha1
import (
"log"
"reflect"
"testing"
)
//go:generate go run asm.go -out sha1.s -stubs stub.go
func TestEmptyString(t *testing.T) {
h := [...]uint32{0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}
m := make([]byte, 64)
m[0] = 0x80
block(&h, m)
expect := [...]uint32{0xda39a3ee, 0x5e6b4b0d, 0x3255bfef, 0x95601890, 0xafd80709}
for i := 0; i < 5; i++ {
log.Printf("h[%d] = %08x", i, h[i])
}
if !reflect.DeepEqual(expect, h) {
t.Fatal("incorrect hash")
}
}

5
examples/sha1/stub.go Normal file
View File

@@ -0,0 +1,5 @@
// Code generated by command: go run asm.go -out sha1.s -stubs stub.go. DO NOT EDIT.
package sha1
func block(h *[5]uint32, m []byte)

View File

@@ -44,6 +44,19 @@ func NewParamAddr(name string, offset int) Mem {
}
}
func NewStackAddr(offset int) Mem {
return Mem{
Disp: offset,
Base: reg.StackPointer,
}
}
func (m Mem) Idx(idx int) Mem {
a := m
a.Disp += idx
return a
}
func (m Mem) Asm() string {
a := m.Symbol.String()
if m.Disp != 0 {