mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-23 13:41:37 +00:00
compiler: rewrite jump targets properly
Old implementation could view 0x62 byte in a script as a JMP instruction irregardless of whether it is a real opcode or a part of a parameter of another instruction. In this commit instructions are decoded together with parameters during jump label rewriting.
This commit is contained in:
parent
cc9ace6426
commit
3e84f2bdf8
3 changed files with 26 additions and 6 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"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/emit"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
|
"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) {
|
func (c *codegen) writeJumps(b []byte) {
|
||||||
for i, op := range b {
|
ctx := vm.NewContext(b)
|
||||||
j := i + 1
|
for op, _, err := ctx.Next(); err == nil && ctx.NextIP() < len(b); op, _, err = ctx.Next() {
|
||||||
switch opcode.Opcode(op) {
|
switch op {
|
||||||
case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL:
|
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 {
|
if int(index) > len(c.l) || int(index) < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
offset := uint16(c.l[index] - i)
|
offset := uint16(c.l[index] - ctx.NextIP() + 3)
|
||||||
binary.LittleEndian.PutUint16(b[j:j+2], offset)
|
binary.LittleEndian.PutUint16(arg, offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,3 +74,14 @@ var sliceTestCases = []testCase{
|
||||||
func TestSliceOperations(t *testing.T) {
|
func TestSliceOperations(t *testing.T) {
|
||||||
runTestCases(t, sliceTestCases)
|
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})
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
// Next returns the next instruction to execute with its parameter if any. After
|
||||||
// its invocation the instruction pointer points to the instruction being
|
// its invocation the instruction pointer points to the instruction being
|
||||||
// returned.
|
// returned.
|
||||||
|
|
Loading…
Reference in a new issue