Implemented calls using memory addresses
This commit is contained in:
parent
ea233d789d
commit
08660ad845
@ -35,9 +35,27 @@ func (mem *Memory) Format(custom string) string {
|
|||||||
tmp.WriteString(strconv.Itoa(int(mem.Offset)))
|
tmp.WriteString(strconv.Itoa(int(mem.Offset)))
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp.WriteString("], ")
|
tmp.WriteString("]")
|
||||||
tmp.WriteString(custom)
|
|
||||||
|
if custom != "" {
|
||||||
|
tmp.WriteString(", ")
|
||||||
|
tmp.WriteString(custom)
|
||||||
|
}
|
||||||
|
|
||||||
tmp.WriteString(", ")
|
tmp.WriteString(", ")
|
||||||
tmp.WriteString(strconv.Itoa(int(mem.Length)))
|
tmp.WriteString(strconv.Itoa(int(mem.Length)))
|
||||||
return tmp.String()
|
return tmp.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String returns a human readable version.
|
||||||
|
func (mem *Memory) String() string {
|
||||||
|
return mem.Format("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory adds an instruction with a memory address.
|
||||||
|
func (a *Assembler) Memory(mnemonic Mnemonic, address Memory) {
|
||||||
|
a.Instructions = append(a.Instructions, Instruction{
|
||||||
|
Mnemonic: mnemonic,
|
||||||
|
Data: &address,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -32,5 +32,8 @@ func (c *compiler) call(x asm.Instruction) {
|
|||||||
|
|
||||||
case *asm.Register:
|
case *asm.Register:
|
||||||
c.code = x86.CallRegister(c.code, data.Register)
|
c.code = x86.CallRegister(c.code, data.Register)
|
||||||
|
|
||||||
|
case *asm.Memory:
|
||||||
|
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
func (c *compiler) dllCall(x asm.Instruction) {
|
func (c *compiler) dllCall(x asm.Instruction) {
|
||||||
size := 4
|
size := 4
|
||||||
c.code = x86.CallAtAddress(c.code, 0x00_00_00_00)
|
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
||||||
position := len(c.code) - size
|
position := len(c.code) - size
|
||||||
label := x.Data.(*asm.Label)
|
label := x.Data.(*asm.Label)
|
||||||
|
|
||||||
|
@ -75,10 +75,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
|
|||||||
f.Register(asm.CALL, value.Register)
|
f.Register(asm.CALL, value.Register)
|
||||||
|
|
||||||
case *eval.Memory:
|
case *eval.Memory:
|
||||||
tmp := f.NewRegister()
|
f.Memory(asm.CALL, value.Memory)
|
||||||
f.MemoryRegister(asm.LOAD, value.Memory, tmp)
|
|
||||||
f.Register(asm.CALL, tmp)
|
|
||||||
f.FreeRegister(tmp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
8
src/register/Memory.go
Normal file
8
src/register/Memory.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package register
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/asm"
|
||||||
|
|
||||||
|
func (f *Machine) Memory(mnemonic asm.Mnemonic, memory asm.Memory) {
|
||||||
|
f.Assembler.Memory(mnemonic, memory)
|
||||||
|
f.postInstruction()
|
||||||
|
}
|
@ -34,9 +34,9 @@ func CallRegister(code []byte, register cpu.Register) []byte {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallAtAddress calls a function at the address stored at the given memory address.
|
// CallAt calls a function at the address stored at the given memory address.
|
||||||
// The memory address is relative to the next instruction.
|
// The memory address is relative to the next instruction.
|
||||||
func CallAtAddress(code []byte, address uint32) []byte {
|
func CallAt(code []byte, address uint32) []byte {
|
||||||
return append(
|
return append(
|
||||||
code,
|
code,
|
||||||
0xFF,
|
0xFF,
|
||||||
@ -47,3 +47,33 @@ func CallAtAddress(code []byte, address uint32) []byte {
|
|||||||
byte(address>>24),
|
byte(address>>24),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CallAtMemory calls a function at the address stored at the given memory address.
|
||||||
|
// The memory address is relative to the next instruction.
|
||||||
|
func CallAtMemory(code []byte, register cpu.Register, offset int8) []byte {
|
||||||
|
mod := AddressMemory
|
||||||
|
|
||||||
|
if offset != 0 || register == RBP || register == R13 {
|
||||||
|
mod = AddressMemoryOffset8
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := byte(0b010)
|
||||||
|
rm := register
|
||||||
|
|
||||||
|
if rm > 0b111 {
|
||||||
|
code = append(code, 0x41)
|
||||||
|
rm &= 0b111
|
||||||
|
}
|
||||||
|
|
||||||
|
code = append(code, 0xFF, ModRM(mod, reg, byte(rm)))
|
||||||
|
|
||||||
|
if register == RSP || register == R12 {
|
||||||
|
code = append(code, SIB(Scale1, 0b100, 0b100))
|
||||||
|
}
|
||||||
|
|
||||||
|
if mod == AddressMemoryOffset8 {
|
||||||
|
code = append(code, byte(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
@ -37,3 +37,51 @@ func TestCallRegister(t *testing.T) {
|
|||||||
assert.DeepEqual(t, code, pattern.Code)
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCallAtMemory(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Register cpu.Register
|
||||||
|
Offset int8
|
||||||
|
Code []byte
|
||||||
|
}{
|
||||||
|
{x86.RAX, 0, []byte{0xFF, 0x10}},
|
||||||
|
{x86.RCX, 0, []byte{0xFF, 0x11}},
|
||||||
|
{x86.RDX, 0, []byte{0xFF, 0x12}},
|
||||||
|
{x86.RBX, 0, []byte{0xFF, 0x13}},
|
||||||
|
{x86.RSP, 0, []byte{0xFF, 0x14, 0x24}},
|
||||||
|
{x86.RBP, 0, []byte{0xFF, 0x55, 0x00}},
|
||||||
|
{x86.RSI, 0, []byte{0xFF, 0x16}},
|
||||||
|
{x86.RDI, 0, []byte{0xFF, 0x17}},
|
||||||
|
{x86.R8, 0, []byte{0x41, 0xFF, 0x10}},
|
||||||
|
{x86.R9, 0, []byte{0x41, 0xFF, 0x11}},
|
||||||
|
{x86.R10, 0, []byte{0x41, 0xFF, 0x12}},
|
||||||
|
{x86.R11, 0, []byte{0x41, 0xFF, 0x13}},
|
||||||
|
{x86.R12, 0, []byte{0x41, 0xFF, 0x14, 0x24}},
|
||||||
|
{x86.R13, 0, []byte{0x41, 0xFF, 0x55, 0x00}},
|
||||||
|
{x86.R14, 0, []byte{0x41, 0xFF, 0x16}},
|
||||||
|
{x86.R15, 0, []byte{0x41, 0xFF, 0x17}},
|
||||||
|
|
||||||
|
{x86.RAX, 1, []byte{0xFF, 0x50, 0x01}},
|
||||||
|
{x86.RCX, 1, []byte{0xFF, 0x51, 0x01}},
|
||||||
|
{x86.RDX, 1, []byte{0xFF, 0x52, 0x01}},
|
||||||
|
{x86.RBX, 1, []byte{0xFF, 0x53, 0x01}},
|
||||||
|
{x86.RSP, 1, []byte{0xFF, 0x54, 0x24, 0x01}},
|
||||||
|
{x86.RBP, 1, []byte{0xFF, 0x55, 0x01}},
|
||||||
|
{x86.RSI, 1, []byte{0xFF, 0x56, 0x01}},
|
||||||
|
{x86.RDI, 1, []byte{0xFF, 0x57, 0x01}},
|
||||||
|
{x86.R8, 1, []byte{0x41, 0xFF, 0x50, 0x01}},
|
||||||
|
{x86.R9, 1, []byte{0x41, 0xFF, 0x51, 0x01}},
|
||||||
|
{x86.R10, 1, []byte{0x41, 0xFF, 0x52, 0x01}},
|
||||||
|
{x86.R11, 1, []byte{0x41, 0xFF, 0x53, 0x01}},
|
||||||
|
{x86.R12, 1, []byte{0x41, 0xFF, 0x54, 0x24, 0x01}},
|
||||||
|
{x86.R13, 1, []byte{0x41, 0xFF, 0x55, 0x01}},
|
||||||
|
{x86.R14, 1, []byte{0x41, 0xFF, 0x56, 0x01}},
|
||||||
|
{x86.R15, 1, []byte{0x41, 0xFF, 0x57, 0x01}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("call [%s+%d]", pattern.Register, pattern.Offset)
|
||||||
|
code := x86.CallAtMemory(nil, pattern.Register, pattern.Offset)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
func TestX86(t *testing.T) {
|
func TestX86(t *testing.T) {
|
||||||
assert.DeepEqual(t, x86.Call(nil, 1), []byte{0xE8, 0x01, 0x00, 0x00, 0x00})
|
assert.DeepEqual(t, x86.Call(nil, 1), []byte{0xE8, 0x01, 0x00, 0x00, 0x00})
|
||||||
assert.DeepEqual(t, x86.CallAtAddress(nil, 1), []byte{0xFF, 0x15, 0x01, 0x00, 0x00, 0x00})
|
assert.DeepEqual(t, x86.CallAt(nil, 1), []byte{0xFF, 0x15, 0x01, 0x00, 0x00, 0x00})
|
||||||
assert.DeepEqual(t, x86.ExtendRAXToRDX(nil), []byte{0x48, 0x99})
|
assert.DeepEqual(t, x86.ExtendRAXToRDX(nil), []byte{0x48, 0x99})
|
||||||
assert.DeepEqual(t, x86.MoveRegisterNumber(nil, 0, 1), []byte{0xB8, 0x01, 0x00, 0x00, 0x00})
|
assert.DeepEqual(t, x86.MoveRegisterNumber(nil, 0, 1), []byte{0xB8, 0x01, 0x00, 0x00, 0x00})
|
||||||
assert.DeepEqual(t, x86.MoveRegisterNumber(nil, 1, 1), []byte{0xB9, 0x01, 0x00, 0x00, 0x00})
|
assert.DeepEqual(t, x86.MoveRegisterNumber(nil, 1, 1), []byte{0xB9, 0x01, 0x00, 0x00, 0x00})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user