Implemented more arm64 instructions
This commit is contained in:
15
lib/sys/sys_linux_arm.q
Normal file
15
lib/sys/sys_linux_arm.q
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
read(fd int, buffer *byte, length int) -> int {
|
||||||
|
return syscall(63, fd, buffer, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
write(fd int, buffer *byte, length int) -> int {
|
||||||
|
return syscall(64, fd, buffer, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
mmap(address int, length uint, protection int, flags int) -> *any {
|
||||||
|
return syscall(222, address, length, protection, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(address *any, length uint) -> int {
|
||||||
|
return syscall(215, address, length)
|
||||||
|
}
|
@ -1,15 +1,8 @@
|
|||||||
package arm
|
package arm
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
// Call branches to a PC-relative offset, setting the register X30 to PC+4.
|
// Call branches to a PC-relative offset, setting the register X30 to PC+4.
|
||||||
// The offset starts from the address of this instruction and is encoded as "imm26" times 4.
|
// The offset starts from the address of this instruction and is encoded as "imm26" times 4.
|
||||||
// This instruction is also known as BL (branch with link).
|
// This instruction is also known as BL (branch with link).
|
||||||
func Call(code []byte, offset uint32) []byte {
|
func Call(offset uint32) uint32 {
|
||||||
return binary.LittleEndian.AppendUint32(code, EncodeCall(offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeCall returns the raw encoding of a call with the given offset.
|
|
||||||
func EncodeCall(offset uint32) uint32 {
|
|
||||||
return uint32(0b100101<<26) | offset
|
return uint32(0b100101<<26) | offset
|
||||||
}
|
}
|
||||||
|
13
src/arm/Load.go
Normal file
13
src/arm/Load.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/cpu"
|
||||||
|
|
||||||
|
// LoadRegister loads from memory into a register.
|
||||||
|
func LoadRegister(destination cpu.Register, base cpu.Register, offset int16, length byte) uint32 {
|
||||||
|
if offset < 0 {
|
||||||
|
offset &= 0xFF
|
||||||
|
offset |= 1 << 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0b11111000010<<21 | uint32(offset)<<12 | uint32(base)<<5 | uint32(destination)
|
||||||
|
}
|
10
src/arm/LoadAddress.go
Normal file
10
src/arm/LoadAddress.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/cpu"
|
||||||
|
|
||||||
|
// LoadAddress calculates the address with the PC-relative offset and writes the result to the destination register.
|
||||||
|
func LoadAddress(destination cpu.Register, offset int) uint32 {
|
||||||
|
hi := uint32(offset) >> 2
|
||||||
|
lo := uint32(offset) & 0b11
|
||||||
|
return lo<<29 | 0b10000<<24 | hi<<5 | uint32(destination)
|
||||||
|
}
|
26
src/arm/LoadAddress_test.go
Normal file
26
src/arm/LoadAddress_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package arm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
|
"git.urbach.dev/go/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadAddress(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Destination cpu.Register
|
||||||
|
Number int
|
||||||
|
Code uint32
|
||||||
|
}{
|
||||||
|
{arm.X0, 56, 0x100001C0},
|
||||||
|
{arm.X1, 80, 0x10000281},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("adr %s, %d", pattern.Destination, pattern.Number)
|
||||||
|
code := arm.LoadAddress(pattern.Destination, pattern.Number)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
31
src/arm/Load_test.go
Normal file
31
src/arm/Load_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package arm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
|
"git.urbach.dev/go/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadRegister(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Destination cpu.Register
|
||||||
|
Base cpu.Register
|
||||||
|
Offset int16
|
||||||
|
Length byte
|
||||||
|
Code uint32
|
||||||
|
}{
|
||||||
|
{arm.X2, arm.X1, -8, 8, 0xF85F8022},
|
||||||
|
{arm.X2, arm.X1, 0, 8, 0xF8400022},
|
||||||
|
{arm.X2, arm.X1, 8, 8, 0xF8408022},
|
||||||
|
{arm.X2, arm.X1, -256, 8, 0xF8500022},
|
||||||
|
{arm.X2, arm.X1, 255, 8, 0xF84FF022},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("ldur %s, [%s, %d] %db", pattern.Destination, pattern.Base, pattern.Offset, pattern.Length)
|
||||||
|
code := arm.LoadRegister(pattern.Destination, pattern.Base, pattern.Offset, pattern.Length)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,27 @@
|
|||||||
package arm
|
package arm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/cpu"
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MoveRegisterRegister copies a register to another register.
|
||||||
|
func MoveRegisterRegister(destination cpu.Register, source cpu.Register) uint32 {
|
||||||
|
return 0b10101010<<24 | uint32(source)<<16 | 0b11111<<5 | uint32(destination)
|
||||||
|
}
|
||||||
|
|
||||||
// MoveRegisterNumber moves an integer into the given register.
|
// MoveRegisterNumber moves an integer into the given register.
|
||||||
func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte {
|
func MoveRegisterNumber(destination cpu.Register, number int) uint32 {
|
||||||
return MoveZero(code, destination, 0, uint16(number))
|
return MoveZero(destination, 0, uint16(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveKeep moves a 16-bit integer into the given register and keeps all other bits.
|
// MoveKeep moves a 16-bit integer into the given register and keeps all other bits.
|
||||||
func MoveKeep(code []byte, destination cpu.Register, halfword int, number uint16) []byte {
|
func MoveKeep(destination cpu.Register, halfword int, number uint16) uint32 {
|
||||||
x := mov(0b11, halfword, number, destination)
|
return mov(0b11, halfword, number, destination)
|
||||||
return binary.LittleEndian.AppendUint32(code, x)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveZero moves a 16-bit integer into the given register and clears all other bits to zero.
|
// MoveZero moves a 16-bit integer into the given register and clears all other bits to zero.
|
||||||
func MoveZero(code []byte, destination cpu.Register, halfword int, number uint16) []byte {
|
func MoveZero(destination cpu.Register, halfword int, number uint16) uint32 {
|
||||||
x := mov(0b10, halfword, number, destination)
|
return mov(0b10, halfword, number, destination)
|
||||||
return binary.LittleEndian.AppendUint32(code, x)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mov encodes a generic move instruction.
|
// mov encodes a generic move instruction.
|
||||||
|
@ -8,19 +8,36 @@ import (
|
|||||||
"git.urbach.dev/go/assert"
|
"git.urbach.dev/go/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMoveRegisterRegister(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Destination cpu.Register
|
||||||
|
Source cpu.Register
|
||||||
|
Code uint32
|
||||||
|
}{
|
||||||
|
{arm.X0, arm.X1, 0xAA0103E0},
|
||||||
|
{arm.X1, arm.X0, 0xAA0003E1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("mov %s, %s", pattern.Destination, pattern.Source)
|
||||||
|
code := arm.MoveRegisterRegister(pattern.Destination, pattern.Source)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMoveKeep(t *testing.T) {
|
func TestMoveKeep(t *testing.T) {
|
||||||
usagePatterns := []struct {
|
usagePatterns := []struct {
|
||||||
Register cpu.Register
|
Register cpu.Register
|
||||||
Number uint16
|
Number uint16
|
||||||
Code []byte
|
Code uint32
|
||||||
}{
|
}{
|
||||||
{arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xF2}},
|
{arm.X0, 0, 0xF2800000},
|
||||||
{arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xF2}},
|
{arm.X0, 1, 0xF2800020},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range usagePatterns {
|
for _, pattern := range usagePatterns {
|
||||||
t.Logf("movk %s, %x", pattern.Register, pattern.Number)
|
t.Logf("movk %s, %x", pattern.Register, pattern.Number)
|
||||||
code := arm.MoveKeep(nil, pattern.Register, 0, pattern.Number)
|
code := arm.MoveKeep(pattern.Register, 0, pattern.Number)
|
||||||
assert.DeepEqual(t, code, pattern.Code)
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,15 +46,15 @@ func TestMoveZero(t *testing.T) {
|
|||||||
usagePatterns := []struct {
|
usagePatterns := []struct {
|
||||||
Register cpu.Register
|
Register cpu.Register
|
||||||
Number uint16
|
Number uint16
|
||||||
Code []byte
|
Code uint32
|
||||||
}{
|
}{
|
||||||
{arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xD2}},
|
{arm.X0, 0, 0xD2800000},
|
||||||
{arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xD2}},
|
{arm.X0, 1, 0xD2800020},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range usagePatterns {
|
for _, pattern := range usagePatterns {
|
||||||
t.Logf("movz %s, %x", pattern.Register, pattern.Number)
|
t.Logf("movz %s, %x", pattern.Register, pattern.Number)
|
||||||
code := arm.MoveZero(nil, pattern.Register, 0, pattern.Number)
|
code := arm.MoveZero(pattern.Register, 0, pattern.Number)
|
||||||
assert.DeepEqual(t, code, pattern.Code)
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package arm
|
package arm
|
||||||
|
|
||||||
// Nop does nothing. This can be used for alignment purposes.
|
// Nop does nothing. This can be used for alignment purposes.
|
||||||
func Nop(code []byte) []byte {
|
func Nop() uint32 {
|
||||||
return append(code, 0x1F, 0x20, 0x03, 0xD5)
|
return 0xD503201F
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package arm
|
package arm
|
||||||
|
|
||||||
// Return transfers program control to the caller.
|
// Return transfers program control to the caller.
|
||||||
func Return(code []byte) []byte {
|
func Return() uint32 {
|
||||||
return append(code, 0xC0, 0x03, 0x5F, 0xD6)
|
return 0xD65F03C0
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package arm
|
package arm
|
||||||
|
|
||||||
// Syscall is the primary way to communicate with the OS kernel.
|
// Syscall is the primary way to communicate with the OS kernel.
|
||||||
func Syscall(code []byte) []byte {
|
func Syscall() uint32 {
|
||||||
return append(code, 0x01, 0x00, 0x00, 0xD4)
|
return 0xD4000001
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestARM(t *testing.T) {
|
func TestARM(t *testing.T) {
|
||||||
assert.DeepEqual(t, arm.Call(nil, 0), []byte{0x00, 0x00, 0x00, 0x94})
|
assert.DeepEqual(t, arm.Call(0), 0x94000000)
|
||||||
assert.DeepEqual(t, arm.MoveRegisterNumber(nil, arm.X0, 42), arm.MoveZero(nil, arm.X0, 0, 42))
|
assert.DeepEqual(t, arm.MoveRegisterNumber(arm.X0, 42), arm.MoveZero(arm.X0, 0, 42))
|
||||||
assert.DeepEqual(t, arm.Nop(nil), []byte{0x1F, 0x20, 0x03, 0xD5})
|
assert.DeepEqual(t, arm.Nop(), 0xD503201F)
|
||||||
assert.DeepEqual(t, arm.Return(nil), []byte{0xC0, 0x03, 0x5F, 0xD6})
|
assert.DeepEqual(t, arm.Return(), 0xD65F03C0)
|
||||||
assert.DeepEqual(t, arm.Syscall(nil), []byte{0x01, 0x00, 0x00, 0xD4})
|
assert.DeepEqual(t, arm.Syscall(), 0xD4000001)
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,19 @@ func (a *Assembler) CanSkipReturn() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
lastMnemonic := a.Instructions[len(a.Instructions)-1].Mnemonic
|
last := a.Instructions[len(a.Instructions)-1]
|
||||||
|
|
||||||
if lastMnemonic == RETURN || lastMnemonic == JUMP {
|
if last.Mnemonic == RETURN || last.Mnemonic == JUMP {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if last.Mnemonic == CALL {
|
||||||
|
label, isLabel := last.Data.(*Label)
|
||||||
|
|
||||||
|
if isLabel && label.String() == "core.exit" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package asmc
|
package asmc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.urbach.dev/cli/q/src/arm"
|
|
||||||
"git.urbach.dev/cli/q/src/asm"
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
"git.urbach.dev/cli/q/src/config"
|
"git.urbach.dev/cli/q/src/config"
|
||||||
"git.urbach.dev/cli/q/src/dll"
|
"git.urbach.dev/cli/q/src/dll"
|
||||||
@ -31,10 +30,6 @@ func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
|||||||
c.compileARM(x)
|
c.compileARM(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.code = arm.MoveRegisterNumber(c.code, arm.X0, 0)
|
|
||||||
c.code = arm.MoveRegisterNumber(c.code, arm.X8, 0x5D)
|
|
||||||
c.code = arm.Syscall(c.code)
|
|
||||||
|
|
||||||
case config.X86:
|
case config.X86:
|
||||||
for _, x := range a.Instructions {
|
for _, x := range a.Instructions {
|
||||||
c.compileX86(x)
|
c.compileX86(x)
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package asmc
|
package asmc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/arm"
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
"git.urbach.dev/cli/q/src/asm"
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
@ -12,11 +15,11 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
case asm.CALL:
|
case asm.CALL:
|
||||||
switch data := x.Data.(type) {
|
switch data := x.Data.(type) {
|
||||||
case *asm.Label:
|
case *asm.Label:
|
||||||
position := len(c.code)
|
position := Address(len(c.code))
|
||||||
c.code = arm.Call(c.code, 0)
|
c.append(arm.Call(0))
|
||||||
|
|
||||||
pointer := &pointer{
|
pointer := &pointer{
|
||||||
Position: Address(position),
|
Position: position,
|
||||||
OpSize: 0,
|
OpSize: 0,
|
||||||
Size: 4,
|
Size: 4,
|
||||||
}
|
}
|
||||||
@ -28,8 +31,8 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
distance := (destination - pointer.Position) / 4
|
distance := (destination - position) / 4
|
||||||
return arm.EncodeCall(distance)
|
return arm.Call(distance)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.codePointers = append(c.codePointers, pointer)
|
c.codePointers = append(c.codePointers, pointer)
|
||||||
@ -37,20 +40,67 @@ func (c *compiler) compileARM(x asm.Instruction) {
|
|||||||
|
|
||||||
case asm.LABEL:
|
case asm.LABEL:
|
||||||
c.codeLabels[x.Data.(*asm.Label).Name] = Address(len(c.code))
|
c.codeLabels[x.Data.(*asm.Label).Name] = Address(len(c.code))
|
||||||
|
c.append(0xa9be7bfd)
|
||||||
|
c.append(0x910003fd)
|
||||||
|
|
||||||
|
case asm.LOAD:
|
||||||
|
switch operands := x.Data.(type) {
|
||||||
|
case *asm.MemoryRegister:
|
||||||
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
|
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int16(operands.Address.Offset), operands.Address.Length))
|
||||||
|
} else {
|
||||||
|
// TODO: LoadDynamicRegister
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case asm.MOVE:
|
case asm.MOVE:
|
||||||
switch operands := x.Data.(type) {
|
switch operands := x.Data.(type) {
|
||||||
|
case *asm.RegisterRegister:
|
||||||
|
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
||||||
|
|
||||||
case *asm.RegisterNumber:
|
case *asm.RegisterNumber:
|
||||||
c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
c.append(arm.MoveRegisterNumber(operands.Register, operands.Number))
|
||||||
|
|
||||||
|
case *asm.RegisterLabel:
|
||||||
|
position := Address(len(c.code))
|
||||||
|
c.append(arm.LoadAddress(operands.Register, 0))
|
||||||
|
|
||||||
|
if strings.HasPrefix(operands.Label, "data ") {
|
||||||
|
c.dataPointers = append(c.dataPointers, &pointer{
|
||||||
|
Position: position,
|
||||||
|
OpSize: 0,
|
||||||
|
Size: 4,
|
||||||
|
Resolve: func() Address {
|
||||||
|
destination, exists := c.dataLabels[operands.Label]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
panic("unknown label")
|
||||||
|
}
|
||||||
|
|
||||||
|
destination += c.dataStart - c.codeStart
|
||||||
|
distance := destination - position + 8
|
||||||
|
return arm.LoadAddress(operands.Register, int(distance))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case asm.RETURN:
|
case asm.RETURN:
|
||||||
c.code = arm.Return(c.code)
|
c.append(0xa8c27bfd)
|
||||||
|
c.append(0xd65f03c0)
|
||||||
|
c.append(arm.Return())
|
||||||
|
|
||||||
case asm.SYSCALL:
|
case asm.SYSCALL:
|
||||||
c.code = arm.Syscall(c.code)
|
c.append(arm.Syscall())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c.code = arm.Nop(c.code)
|
panic("unknown mnemonic: " + x.Mnemonic.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *compiler) append(code uint32) {
|
||||||
|
c.code = binary.LittleEndian.AppendUint32(c.code, code)
|
||||||
|
}
|
||||||
|
@ -12,4 +12,5 @@ type compiler struct {
|
|||||||
dllPointers []*pointer
|
dllPointers []*pointer
|
||||||
dlls dll.List
|
dlls dll.List
|
||||||
codeStart Address
|
codeStart Address
|
||||||
|
dataStart Address
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ func (c *compiler) load(x asm.Instruction) {
|
|||||||
switch operands := x.Data.(type) {
|
switch operands := x.Data.(type) {
|
||||||
case *asm.MemoryRegister:
|
case *asm.MemoryRegister:
|
||||||
if operands.Address.OffsetRegister == math.MaxUint8 {
|
if operands.Address.OffsetRegister == math.MaxUint8 {
|
||||||
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Offset, operands.Address.Length, operands.Address.Base)
|
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
||||||
} else {
|
} else {
|
||||||
c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.OffsetRegister, operands.Address.Length, operands.Address.Base)
|
c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func (c *compiler) move(x asm.Instruction) {
|
|||||||
panic("unknown label")
|
panic("unknown label")
|
||||||
}
|
}
|
||||||
|
|
||||||
return destination
|
return config.BaseAddress + c.dataStart + destination + 8
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,16 +77,16 @@ restart:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dataStart, _ := fs.Align(c.codeStart+Address(len(c.code)), config.Align)
|
c.dataStart, _ = fs.Align(c.codeStart+Address(len(c.code)), config.Align)
|
||||||
|
|
||||||
for _, pointer := range c.dataPointers {
|
for _, pointer := range c.dataPointers {
|
||||||
address := config.BaseAddress + dataStart + pointer.Resolve() + 8
|
address := pointer.Resolve()
|
||||||
slice := c.code[pointer.Position : pointer.Position+4]
|
slice := c.code[pointer.Position : pointer.Position+Address(pointer.Size)]
|
||||||
binary.LittleEndian.PutUint32(slice, uint32(address))
|
binary.LittleEndian.PutUint32(slice, uint32(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TargetOS == config.Windows {
|
if config.TargetOS == config.Windows {
|
||||||
importsStart, _ := fs.Align(dataStart+Address(len(c.data)), config.Align)
|
importsStart, _ := fs.Align(c.dataStart+Address(len(c.data)), config.Align)
|
||||||
|
|
||||||
for _, pointer := range c.dllPointers {
|
for _, pointer := range c.dllPointers {
|
||||||
destination := importsStart + pointer.Resolve()
|
destination := importsStart + pointer.Resolve()
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"git.urbach.dev/cli/q/src/scope"
|
"git.urbach.dev/cli/q/src/scope"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
"git.urbach.dev/cli/q/src/types"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
"git.urbach.dev/cli/q/src/x86"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolveTypes parses the input and output types.
|
// ResolveTypes parses the input and output types.
|
||||||
@ -34,7 +33,7 @@ func (f *Function) ResolveTypes() error {
|
|||||||
Name: param.name,
|
Name: param.name,
|
||||||
Value: eval.Register{
|
Value: eval.Register{
|
||||||
Typ: param.typ,
|
Typ: param.typ,
|
||||||
Register: x86.InputRegisters[i],
|
Register: f.CPU.Input[i],
|
||||||
Alive: uses,
|
Alive: uses,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -3,6 +3,6 @@ package x86
|
|||||||
import "git.urbach.dev/cli/q/src/cpu"
|
import "git.urbach.dev/cli/q/src/cpu"
|
||||||
|
|
||||||
// LoadRegister loads from memory into a register.
|
// LoadRegister loads from memory into a register.
|
||||||
func LoadRegister(code []byte, destination cpu.Register, offset int8, length byte, source cpu.Register) []byte {
|
func LoadRegister(code []byte, destination cpu.Register, base cpu.Register, offset int8, length byte) []byte {
|
||||||
return memoryAccess(code, 0x8A, 0x8B, source, offset, length, destination)
|
return memoryAccess(code, 0x8A, 0x8B, base, offset, length, destination)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@ package x86
|
|||||||
import "git.urbach.dev/cli/q/src/cpu"
|
import "git.urbach.dev/cli/q/src/cpu"
|
||||||
|
|
||||||
// LoadDynamicRegister loads from memory with a register offset into a register.
|
// LoadDynamicRegister loads from memory with a register offset into a register.
|
||||||
func LoadDynamicRegister(code []byte, destination cpu.Register, offset cpu.Register, length byte, source cpu.Register) []byte {
|
func LoadDynamicRegister(code []byte, destination cpu.Register, base cpu.Register, offset cpu.Register, length byte) []byte {
|
||||||
return memoryAccessDynamic(code, 0x8A, 0x8B, source, offset, length, destination)
|
return memoryAccessDynamic(code, 0x8A, 0x8B, base, offset, length, destination)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func TestLoadDynamicRegister(t *testing.T) {
|
|||||||
usagePatterns := []struct {
|
usagePatterns := []struct {
|
||||||
Destination cpu.Register
|
Destination cpu.Register
|
||||||
Length byte
|
Length byte
|
||||||
Source cpu.Register
|
Base cpu.Register
|
||||||
OffsetRegister cpu.Register
|
OffsetRegister cpu.Register
|
||||||
Code []byte
|
Code []byte
|
||||||
}{
|
}{
|
||||||
@ -83,8 +83,8 @@ func TestLoadDynamicRegister(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range usagePatterns {
|
for _, pattern := range usagePatterns {
|
||||||
t.Logf("load %dB %s, [%s+%s]", pattern.Length, pattern.Destination, pattern.Source, pattern.OffsetRegister)
|
t.Logf("load %dB %s, [%s+%s]", pattern.Length, pattern.Destination, pattern.Base, pattern.OffsetRegister)
|
||||||
code := x86.LoadDynamicRegister(nil, pattern.Destination, pattern.OffsetRegister, pattern.Length, pattern.Source)
|
code := x86.LoadDynamicRegister(nil, pattern.Destination, pattern.Base, pattern.OffsetRegister, pattern.Length)
|
||||||
assert.DeepEqual(t, code, pattern.Code)
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func TestLoadRegister(t *testing.T) {
|
func TestLoadRegister(t *testing.T) {
|
||||||
usagePatterns := []struct {
|
usagePatterns := []struct {
|
||||||
Destination cpu.Register
|
Destination cpu.Register
|
||||||
Source cpu.Register
|
Base cpu.Register
|
||||||
Offset int8
|
Offset int8
|
||||||
Length byte
|
Length byte
|
||||||
Code []byte
|
Code []byte
|
||||||
@ -150,8 +150,8 @@ func TestLoadRegister(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pattern := range usagePatterns {
|
for _, pattern := range usagePatterns {
|
||||||
t.Logf("load %dB %s, [%s+%d]", pattern.Length, pattern.Destination, pattern.Source, pattern.Offset)
|
t.Logf("load %dB %s, [%s+%d]", pattern.Length, pattern.Destination, pattern.Base, pattern.Offset)
|
||||||
code := x86.LoadRegister(nil, pattern.Destination, pattern.Offset, pattern.Length, pattern.Source)
|
code := x86.LoadRegister(nil, pattern.Destination, pattern.Base, pattern.Offset, pattern.Length)
|
||||||
assert.DeepEqual(t, code, pattern.Code)
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ func MoveRegisterNumber32(code []byte, destination cpu.Register, number int) []b
|
|||||||
return binary.LittleEndian.AppendUint32(code, uint32(number))
|
return binary.LittleEndian.AppendUint32(code, uint32(number))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveRegisterRegister moves a register value into another register.
|
// MoveRegisterRegister copies a register to another register.
|
||||||
func MoveRegisterRegister(code []byte, destination cpu.Register, source cpu.Register) []byte {
|
func MoveRegisterRegister(code []byte, destination cpu.Register, source cpu.Register) []byte {
|
||||||
return encode(code, AddressDirect, source, destination, 8, 0x89)
|
return encode(code, AddressDirect, source, destination, 8, 0x89)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user