diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 8836cc342..9a9b3aa61 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -14,6 +14,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/encoding/address" "github.com/CityOfZion/neo-go/pkg/io" + "github.com/CityOfZion/neo-go/pkg/vm" "github.com/CityOfZion/neo-go/pkg/vm/emit" "github.com/CityOfZion/neo-go/pkg/vm/opcode" ) @@ -1045,16 +1046,19 @@ func (c *codegen) resolveFuncDecls(f *ast.File) { } func (c *codegen) writeJumps(b []byte) { - for i, op := range b { - j := i + 1 - switch opcode.Opcode(op) { + ctx := vm.NewContext(b) + for op, _, err := ctx.Next(); err == nil && ctx.NextIP() < len(b); op, _, err = ctx.Next() { + switch op { case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL: - index := int16(binary.LittleEndian.Uint16(b[j : j+2])) + // we can't use arg returned by ctx.Next() because it is copied + arg := b[ctx.NextIP()-2:] + + index := int16(binary.LittleEndian.Uint16(arg)) if int(index) > len(c.l) || int(index) < 0 { continue } - offset := uint16(c.l[index] - i) - binary.LittleEndian.PutUint16(b[j:j+2], offset) + offset := uint16(c.l[index] - ctx.NextIP() + 3) + binary.LittleEndian.PutUint16(arg, offset) } } } diff --git a/pkg/compiler/slice_test.go b/pkg/compiler/slice_test.go index 5b113ccdb..1fc3abc5b 100644 --- a/pkg/compiler/slice_test.go +++ b/pkg/compiler/slice_test.go @@ -74,3 +74,14 @@ var sliceTestCases = []testCase{ func TestSliceOperations(t *testing.T) { runTestCases(t, sliceTestCases) } + +func TestJumps(t *testing.T) { + src := ` + package foo + func Main() []byte { + buf := []byte{0x62, 0x01, 0x00} + return buf + } + ` + eval(t, src, []byte{0x62, 0x01, 0x00}) +} diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 3b689cedf..65a01fde0 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -47,6 +47,11 @@ func NewContext(b []byte) *Context { } } +// NextIP returns next instruction pointer. +func (c *Context) NextIP() int { + return c.nextip +} + // Next returns the next instruction to execute with its parameter if any. After // its invocation the instruction pointer points to the instruction being // returned.