Refactored assembly compilation
This commit is contained in:
320
src/asmc/ARM.go
320
src/asmc/ARM.go
@ -1,320 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
)
|
||||
|
||||
func (c *compiler) ARM(x asm.Instruction) {
|
||||
switch x.Mnemonic {
|
||||
case asm.MOVE:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
||||
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.LoadAddress(operands.Register, 0))
|
||||
|
||||
if operands.Label.Type == asm.DataLabel {
|
||||
c.dataPointers = append(c.dataPointers, &pointer{
|
||||
Position: position,
|
||||
OpSize: 0,
|
||||
Size: 4,
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.dataLabels[operands.Label.Name]
|
||||
|
||||
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.CALL:
|
||||
switch x.Type {
|
||||
case asm.TypeLabel:
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.Call(0))
|
||||
|
||||
pointer := &pointer{
|
||||
Position: position,
|
||||
OpSize: 0,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := (destination - position) / 4
|
||||
return arm.Call(distance)
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.LABEL:
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
|
||||
if label.Type == asm.FunctionLabel {
|
||||
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
|
||||
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
|
||||
}
|
||||
|
||||
case asm.LOAD:
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
case asm.STORE:
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.append(arm.StoreRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.TypeMemoryNumber:
|
||||
operands := c.assembler.Param.MemoryNumber[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operands.Number)
|
||||
c.append(arm.StoreRegister(arm.TMP, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
case asm.RETURN:
|
||||
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
||||
c.append(arm.Return())
|
||||
|
||||
case asm.SYSCALL:
|
||||
c.append(arm.Syscall())
|
||||
|
||||
case asm.PUSH:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operand := c.assembler.Param.Register[x.Index]
|
||||
code, _ := arm.SubRegisterNumber(arm.SP, arm.SP, 16)
|
||||
c.append(code)
|
||||
c.append(arm.StoreRegister(operand.Register, arm.SP, 0, 8))
|
||||
}
|
||||
|
||||
case asm.POP:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operand := c.assembler.Param.Register[x.Index]
|
||||
c.append(arm.LoadRegister(operand.Register, arm.SP, 0, 8))
|
||||
code, _ := arm.AddRegisterNumber(arm.SP, arm.SP, 16)
|
||||
c.append(code)
|
||||
}
|
||||
|
||||
case asm.AND:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.AndRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.AndRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.AndRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.OR:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.OrRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.OrRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.OrRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.XOR:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.XorRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.XorRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.XorRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.ADD:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.AddRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.AddRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.SUB:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.SubRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.SubRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.COMPARE:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
code, encodable := arm.CompareRegisterNumber(operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.CompareRegisterRegister(operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.CompareRegisterRegister(operand.Destination, operand.Source))
|
||||
}
|
||||
|
||||
case asm.DIV:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.DivSigned(operand.Destination, operand.Destination, operand.Source))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.DivSigned(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
|
||||
case asm.MUL:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.MulRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.MulRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
|
||||
case asm.MODULO:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.append(arm.DivSigned(arm.TMP, operand.Destination, operand.Source))
|
||||
c.append(arm.MultiplySubtract(operand.Destination, arm.TMP, operand.Source, operand.Destination))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.DivSigned(arm.TMP2, operand.Register, arm.TMP))
|
||||
c.append(arm.MultiplySubtract(operand.Register, arm.TMP2, arm.TMP, operand.Register))
|
||||
}
|
||||
|
||||
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
|
||||
c.jumpARM(x)
|
||||
|
||||
case asm.SHIFTL:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.append(arm.ShiftLeftNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.SHIFTRS:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.append(arm.ShiftRightSignedNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.NEGATE:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.append(arm.NegateRegister(operands.Register, operands.Register))
|
||||
}
|
||||
|
||||
default:
|
||||
panic("unknown mnemonic: " + x.Mnemonic.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) append(code uint32) {
|
||||
c.code = binary.LittleEndian.AppendUint32(c.code, code)
|
||||
}
|
@ -27,13 +27,17 @@ func Finalize(a *asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
||||
|
||||
switch config.TargetArch {
|
||||
case config.ARM:
|
||||
armc := armCompiler{compiler: &c}
|
||||
|
||||
for _, x := range a.Instructions {
|
||||
c.ARM(x)
|
||||
armc.Compile(x)
|
||||
}
|
||||
|
||||
case config.X86:
|
||||
x86c := x86Compiler{compiler: &c}
|
||||
|
||||
for _, x := range a.Instructions {
|
||||
c.X86(x)
|
||||
x86c.Compile(x)
|
||||
}
|
||||
}
|
||||
|
||||
|
218
src/asmc/X86.go
218
src/asmc/X86.go
@ -1,218 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) X86(x asm.Instruction) {
|
||||
switch x.Mnemonic {
|
||||
case asm.MOVE:
|
||||
c.move(x)
|
||||
|
||||
case asm.CALL:
|
||||
c.call(x)
|
||||
|
||||
case asm.LABEL:
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
|
||||
case asm.LOAD:
|
||||
c.load(x)
|
||||
|
||||
case asm.STORE:
|
||||
c.store(x)
|
||||
|
||||
case asm.RETURN:
|
||||
c.code = x86.Return(c.code)
|
||||
|
||||
case asm.SYSCALL:
|
||||
c.code = x86.Syscall(c.code)
|
||||
|
||||
case asm.ADD:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.AddRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.AddRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.AND:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.AndRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.AndRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.SUB:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.SubRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.SubRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.MUL:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.MulRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.MulRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.DIV:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Register)
|
||||
}
|
||||
|
||||
c.code = x86.MoveRegisterNumber(c.code, x86.TMP, operands.Number)
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, x86.TMP)
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Register, x86.RAX)
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, operands.Source)
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, x86.RAX)
|
||||
}
|
||||
}
|
||||
|
||||
case asm.MODULO:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Register)
|
||||
}
|
||||
|
||||
c.code = x86.MoveRegisterNumber(c.code, x86.TMP, operands.Number)
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, x86.TMP)
|
||||
|
||||
if operands.Register != x86.RDX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Register, x86.RDX)
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, operands.Source)
|
||||
|
||||
if operands.Destination != x86.RDX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, x86.RDX)
|
||||
}
|
||||
}
|
||||
|
||||
case asm.COMMENT:
|
||||
return
|
||||
|
||||
case asm.COMPARE:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.CompareRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.CompareRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.DLLCALL:
|
||||
c.dllCall(x)
|
||||
|
||||
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
|
||||
c.jumpX86(x)
|
||||
|
||||
case asm.NEGATE:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.NegateRegister(c.code, operands.Register)
|
||||
}
|
||||
|
||||
case asm.OR:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.OrRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.OrRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
case asm.POP:
|
||||
switch x.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.PopRegister(c.code, operands.Register)
|
||||
}
|
||||
|
||||
case asm.PUSH:
|
||||
switch x.Type {
|
||||
case asm.TypeNumber:
|
||||
operands := c.assembler.Param.Number[x.Index]
|
||||
c.code = x86.PushNumber(c.code, int32(operands.Number))
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.PushRegister(c.code, operands.Register)
|
||||
}
|
||||
|
||||
case asm.SHIFTL:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.SHIFTRS:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.ShiftRightSignedNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
case asm.XOR:
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.XorRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.XorRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
|
||||
default:
|
||||
panic("unknown mnemonic: " + x.Mnemonic.String())
|
||||
}
|
||||
}
|
420
src/asmc/armCompiler.go
Normal file
420
src/asmc/armCompiler.go
Normal file
@ -0,0 +1,420 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
)
|
||||
|
||||
type armCompiler struct {
|
||||
*compiler
|
||||
}
|
||||
|
||||
func (c *armCompiler) Compile(instruction asm.Instruction) {
|
||||
switch instruction.Mnemonic {
|
||||
case asm.MOVE:
|
||||
c.handleMoveInstruction(instruction)
|
||||
case asm.CALL:
|
||||
c.handleCallInstruction(instruction)
|
||||
case asm.LABEL:
|
||||
c.handleLabelInstruction(instruction)
|
||||
case asm.LOAD:
|
||||
c.handleLoadInstruction(instruction)
|
||||
case asm.STORE:
|
||||
c.handleStoreInstruction(instruction)
|
||||
case asm.RETURN:
|
||||
c.append(arm.LoadPair(arm.FP, arm.LR, arm.SP, 16))
|
||||
c.append(arm.Return())
|
||||
case asm.SYSCALL:
|
||||
c.append(arm.Syscall())
|
||||
case asm.PUSH:
|
||||
c.handlePushInstruction(instruction)
|
||||
case asm.POP:
|
||||
c.handlePopInstruction(instruction)
|
||||
case asm.AND:
|
||||
c.handleAndInstruction(instruction)
|
||||
case asm.OR:
|
||||
c.handleOrInstruction(instruction)
|
||||
case asm.XOR:
|
||||
c.handleXorInstruction(instruction)
|
||||
case asm.ADD:
|
||||
c.handleAddInstruction(instruction)
|
||||
case asm.SUB:
|
||||
c.handleSubInstruction(instruction)
|
||||
case asm.COMPARE:
|
||||
c.handleCompareInstruction(instruction)
|
||||
case asm.DIV:
|
||||
c.handleDivInstruction(instruction)
|
||||
case asm.MUL:
|
||||
c.handleMulInstruction(instruction)
|
||||
case asm.MODULO:
|
||||
c.handleModuloInstruction(instruction)
|
||||
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
|
||||
c.handleJumpInstruction(instruction)
|
||||
case asm.SHIFTL:
|
||||
c.handleShiftLeftInstruction(instruction)
|
||||
case asm.SHIFTRS:
|
||||
c.handleShiftRightSignedInstruction(instruction)
|
||||
case asm.NEGATE:
|
||||
c.handleNegateInstruction(instruction)
|
||||
default:
|
||||
panic("unknown mnemonic: " + instruction.Mnemonic.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleMoveInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.MoveRegisterRegister(operands.Destination, operands.Source))
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[instruction.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.LoadAddress(operands.Register, 0))
|
||||
|
||||
if operands.Label.Type == asm.DataLabel {
|
||||
c.dataPointers = append(c.dataPointers, c.createDataPointer(operands, position))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleCallInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeLabel:
|
||||
label := c.assembler.Param.Label[instruction.Index]
|
||||
position := Address(len(c.code))
|
||||
c.append(arm.Call(0))
|
||||
|
||||
pointer := &pointer{
|
||||
Position: position,
|
||||
OpSize: 0,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
distance := (destination - position) / 4
|
||||
return arm.Call(distance)
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleLabelInstruction(instruction asm.Instruction) {
|
||||
label := c.assembler.Param.Label[instruction.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
|
||||
if label.Type == asm.FunctionLabel {
|
||||
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
|
||||
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleLoadInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.append(arm.LoadRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleStoreInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.append(arm.StoreRegister(operands.Register, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
case asm.TypeMemoryNumber:
|
||||
operands := c.assembler.Param.MemoryNumber[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operands.Number)
|
||||
c.append(arm.StoreRegister(arm.TMP, operands.Address.Base, int(operands.Address.Offset), operands.Address.Length))
|
||||
} else {
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handlePushInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegister:
|
||||
operand := c.assembler.Param.Register[instruction.Index]
|
||||
code, _ := arm.SubRegisterNumber(arm.SP, arm.SP, 16)
|
||||
c.append(code)
|
||||
c.append(arm.StoreRegister(operand.Register, arm.SP, 0, 8))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handlePopInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegister:
|
||||
operand := c.assembler.Param.Register[instruction.Index]
|
||||
c.append(arm.LoadRegister(operand.Register, arm.SP, 0, 8))
|
||||
code, _ := arm.AddRegisterNumber(arm.SP, arm.SP, 16)
|
||||
c.append(code)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleAndInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.AndRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.AndRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.AndRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleOrInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.OrRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.OrRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.OrRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleXorInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.XorRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumberMI(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.XorRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.XorRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleAddInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.AddRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.AddRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.AddRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleSubInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.SubRegisterNumber(operand.Register, operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.SubRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.SubRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleCompareInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
code, encodable := arm.CompareRegisterNumber(operand.Register, operand.Number)
|
||||
|
||||
if encodable {
|
||||
c.append(code)
|
||||
} else {
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.CompareRegisterRegister(operand.Register, arm.TMP))
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.CompareRegisterRegister(operand.Destination, operand.Source))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleDivInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.DivSigned(operand.Destination, operand.Destination, operand.Source))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.DivSigned(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleMulInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.MulRegisterRegister(operand.Destination, operand.Destination, operand.Source))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.MulRegisterRegister(operand.Register, operand.Register, arm.TMP))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleModuloInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterRegister:
|
||||
operand := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.append(arm.DivSigned(arm.TMP, operand.Destination, operand.Source))
|
||||
c.append(arm.MultiplySubtract(operand.Destination, arm.TMP, operand.Source, operand.Destination))
|
||||
case asm.TypeRegisterNumber:
|
||||
operand := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = arm.MoveRegisterNumber(c.code, arm.TMP, operand.Number)
|
||||
c.append(arm.DivSigned(arm.TMP2, operand.Register, arm.TMP))
|
||||
c.append(arm.MultiplySubtract(operand.Register, arm.TMP2, arm.TMP, operand.Register))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleJumpInstruction(x asm.Instruction) {
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
mnemonic := x.Mnemonic
|
||||
position := Address(len(c.code))
|
||||
|
||||
pointer := &pointer{
|
||||
Position: position,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
c.append(arm.Nop())
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := (int(destination) - int(position)) / 4
|
||||
|
||||
switch mnemonic {
|
||||
case asm.JE:
|
||||
return arm.JumpIfEqual(distance)
|
||||
case asm.JNE:
|
||||
return arm.JumpIfNotEqual(distance)
|
||||
case asm.JG:
|
||||
return arm.JumpIfGreater(distance)
|
||||
case asm.JGE:
|
||||
return arm.JumpIfGreaterOrEqual(distance)
|
||||
case asm.JL:
|
||||
return arm.JumpIfLess(distance)
|
||||
case asm.JLE:
|
||||
return arm.JumpIfLessOrEqual(distance)
|
||||
case asm.JUMP:
|
||||
return arm.Jump(distance)
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleShiftLeftInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.append(arm.ShiftLeftNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleShiftRightSignedInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.append(arm.ShiftRightSignedNumber(operands.Register, operands.Register, operands.Number&0b111111))
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) handleNegateInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[instruction.Index]
|
||||
c.append(arm.NegateRegister(operands.Register, operands.Register))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *armCompiler) createDataPointer(operands asm.RegisterLabel, position Address) *pointer {
|
||||
return &pointer{
|
||||
Position: position,
|
||||
OpSize: 0,
|
||||
Size: 4,
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.dataLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
destination += c.dataStart - c.codeStart
|
||||
distance := destination - position + 8
|
||||
return arm.LoadAddress(operands.Register, int(distance))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) append(code uint32) {
|
||||
c.code = binary.LittleEndian.AppendUint32(c.code, code)
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) call(x asm.Instruction) {
|
||||
switch x.Type {
|
||||
case asm.TypeLabel:
|
||||
data := c.assembler.Param.Label[x.Index]
|
||||
c.code = x86.Call(c.code, 0x00_00_00_00)
|
||||
size := 4
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: 1,
|
||||
Size: uint8(size),
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[data.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
||||
}
|
||||
|
||||
distance := destination - (pointer.Position + Address(pointer.Size))
|
||||
return distance
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
|
||||
case asm.TypeRegister:
|
||||
data := c.assembler.Param.Register[x.Index]
|
||||
c.code = x86.CallRegister(c.code, data.Register)
|
||||
|
||||
case asm.TypeMemory:
|
||||
data := c.assembler.Param.Memory[x.Index]
|
||||
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) dllCall(x asm.Instruction) {
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
||||
next := Address(len(c.code))
|
||||
position := next - 4
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(position),
|
||||
OpSize: 2,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
dot := strings.Index(label.Name, ".")
|
||||
library := label.Name[:dot]
|
||||
funcName := label.Name[dot+1:]
|
||||
index := c.dlls.Index(library, funcName)
|
||||
|
||||
if index == -1 {
|
||||
panic("unknown DLL function " + label.Name)
|
||||
}
|
||||
|
||||
destination := c.importsStart + Address(index*8)
|
||||
from := c.codeStart + next
|
||||
return destination - from
|
||||
}
|
||||
|
||||
c.dllPointers = append(c.dllPointers, pointer)
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/arm"
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
)
|
||||
|
||||
func (c *compiler) jumpARM(x asm.Instruction) {
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
mnemonic := x.Mnemonic
|
||||
position := Address(len(c.code))
|
||||
|
||||
pointer := &pointer{
|
||||
Position: position,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
c.append(arm.Nop())
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := (int(destination) - int(position)) / 4
|
||||
|
||||
switch mnemonic {
|
||||
case asm.JE:
|
||||
return arm.JumpIfEqual(distance)
|
||||
case asm.JNE:
|
||||
return arm.JumpIfNotEqual(distance)
|
||||
case asm.JG:
|
||||
return arm.JumpIfGreater(distance)
|
||||
case asm.JGE:
|
||||
return arm.JumpIfGreaterOrEqual(distance)
|
||||
case asm.JL:
|
||||
return arm.JumpIfLess(distance)
|
||||
case asm.JLE:
|
||||
return arm.JumpIfLessOrEqual(distance)
|
||||
case asm.JUMP:
|
||||
return arm.Jump(distance)
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) jumpX86(x asm.Instruction) {
|
||||
switch x.Mnemonic {
|
||||
case asm.JE:
|
||||
c.code = x86.Jump8IfEqual(c.code, 0x00)
|
||||
case asm.JNE:
|
||||
c.code = x86.Jump8IfNotEqual(c.code, 0x00)
|
||||
case asm.JG:
|
||||
c.code = x86.Jump8IfGreater(c.code, 0x00)
|
||||
case asm.JGE:
|
||||
c.code = x86.Jump8IfGreaterOrEqual(c.code, 0x00)
|
||||
case asm.JL:
|
||||
c.code = x86.Jump8IfLess(c.code, 0x00)
|
||||
case asm.JLE:
|
||||
c.code = x86.Jump8IfLessOrEqual(c.code, 0x00)
|
||||
case asm.JUMP:
|
||||
c.code = x86.Jump8(c.code, 0x00)
|
||||
}
|
||||
|
||||
label := c.assembler.Param.Label[x.Index]
|
||||
size := 1
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: 1,
|
||||
Size: uint8(size),
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := destination - (pointer.Position + Address(pointer.Size))
|
||||
return distance
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) load(x asm.Instruction) {
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
||||
} else {
|
||||
c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) move(x asm.Instruction) {
|
||||
switch x.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[x.Index]
|
||||
c.code = x86.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[x.Index]
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[x.Index]
|
||||
start := Address(len(c.code))
|
||||
c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00)
|
||||
end := Address(len(c.code))
|
||||
position := end - 4
|
||||
opSize := position - start
|
||||
|
||||
if operands.Label.Type == asm.DataLabel {
|
||||
c.dataPointers = append(c.dataPointers, &pointer{
|
||||
Position: position,
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(4),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.dataLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
destination += c.dataStart - c.codeStart
|
||||
distance := destination - end
|
||||
return distance + 8
|
||||
},
|
||||
})
|
||||
} else {
|
||||
c.codePointers = append(c.codePointers, &pointer{
|
||||
Position: position,
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(4),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.codeLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
return destination - end
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/config"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
func (c *compiler) store(x asm.Instruction) {
|
||||
switch x.Type {
|
||||
case asm.TypeMemoryNumber:
|
||||
operands := c.assembler.Param.MemoryNumber[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Number)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Number)
|
||||
}
|
||||
case asm.TypeMemoryLabel:
|
||||
operands := c.assembler.Param.MemoryLabel[x.Index]
|
||||
start := len(c.code)
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, 0b00_00_00_00)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, 0b00_00_00_00)
|
||||
}
|
||||
|
||||
size := 4
|
||||
opSize := len(c.code) - size - start
|
||||
|
||||
c.codePointers = append(c.codePointers, &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(size),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.codeLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
return config.BaseAddress + c.codeStart + destination
|
||||
},
|
||||
})
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[x.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreRegister(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Register)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicRegister(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Register)
|
||||
}
|
||||
}
|
||||
}
|
474
src/asmc/x86Compiler.go
Normal file
474
src/asmc/x86Compiler.go
Normal file
@ -0,0 +1,474 @@
|
||||
package asmc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.urbach.dev/cli/q/src/asm"
|
||||
"git.urbach.dev/cli/q/src/config"
|
||||
"git.urbach.dev/cli/q/src/x86"
|
||||
)
|
||||
|
||||
type x86Compiler struct {
|
||||
*compiler
|
||||
}
|
||||
|
||||
func (c *x86Compiler) Compile(instruction asm.Instruction) {
|
||||
switch instruction.Mnemonic {
|
||||
case asm.MOVE:
|
||||
c.handleMoveInstruction(instruction)
|
||||
case asm.CALL:
|
||||
c.handleCallInstruction(instruction)
|
||||
case asm.LABEL:
|
||||
label := c.assembler.Param.Label[instruction.Index]
|
||||
c.codeLabels[label.Name] = Address(len(c.code))
|
||||
case asm.LOAD:
|
||||
c.handleLoadInstruction(instruction)
|
||||
case asm.STORE:
|
||||
c.handleStoreInstruction(instruction)
|
||||
case asm.RETURN:
|
||||
c.code = x86.Return(c.code)
|
||||
case asm.SYSCALL:
|
||||
c.code = x86.Syscall(c.code)
|
||||
case asm.ADD:
|
||||
c.handleAddInstruction(instruction)
|
||||
case asm.AND:
|
||||
c.handleAndInstruction(instruction)
|
||||
case asm.DIV:
|
||||
c.handleDivInstruction(instruction)
|
||||
case asm.MODULO:
|
||||
c.handleModuloInstruction(instruction)
|
||||
case asm.MUL:
|
||||
c.handleMulInstruction(instruction)
|
||||
case asm.OR:
|
||||
c.handleOrInstruction(instruction)
|
||||
case asm.SUB:
|
||||
c.handleSubInstruction(instruction)
|
||||
case asm.XOR:
|
||||
c.handleXorInstruction(instruction)
|
||||
case asm.NEGATE:
|
||||
c.handleNegateInstruction(instruction)
|
||||
case asm.POP:
|
||||
c.handlePopInstruction(instruction)
|
||||
case asm.PUSH:
|
||||
c.handlePushInstruction(instruction)
|
||||
case asm.SHIFTL:
|
||||
c.handleShiftLeftInstruction(instruction)
|
||||
case asm.SHIFTRS:
|
||||
c.handleShiftRightSignedInstruction(instruction)
|
||||
case asm.COMPARE:
|
||||
c.handleCompareInstruction(instruction)
|
||||
case asm.DLLCALL:
|
||||
c.handleDllCallInstruction(instruction)
|
||||
case asm.JE, asm.JNE, asm.JG, asm.JGE, asm.JL, asm.JLE, asm.JUMP:
|
||||
c.handleJumpInstruction(instruction)
|
||||
default:
|
||||
panic("unknown mnemonic: " + instruction.Mnemonic.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleMoveInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
case asm.TypeRegisterLabel:
|
||||
operands := c.assembler.Param.RegisterLabel[instruction.Index]
|
||||
start := Address(len(c.code))
|
||||
c.code = x86.LoadAddress(c.code, operands.Register, 0x00_00_00_00)
|
||||
end := Address(len(c.code))
|
||||
position := end - 4
|
||||
opSize := position - start
|
||||
|
||||
if operands.Label.Type == asm.DataLabel {
|
||||
c.dataPointers = append(c.dataPointers, &pointer{
|
||||
Position: position,
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(4),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.dataLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
destination += c.dataStart - c.codeStart
|
||||
distance := destination - end
|
||||
return distance + 8
|
||||
},
|
||||
})
|
||||
} else {
|
||||
c.codePointers = append(c.codePointers, &pointer{
|
||||
Position: position,
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(4),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.codeLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
return destination - end
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleCallInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeLabel:
|
||||
data := c.assembler.Param.Label[instruction.Index]
|
||||
c.code = x86.Call(c.code, 0x00_00_00_00)
|
||||
size := 4
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: 1,
|
||||
Size: uint8(size),
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[data.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", data.Name))
|
||||
}
|
||||
|
||||
distance := destination - (pointer.Position + Address(pointer.Size))
|
||||
return distance
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
case asm.TypeRegister:
|
||||
data := c.assembler.Param.Register[instruction.Index]
|
||||
c.code = x86.CallRegister(c.code, data.Register)
|
||||
case asm.TypeMemory:
|
||||
data := c.assembler.Param.Memory[instruction.Index]
|
||||
c.code = x86.CallAtMemory(c.code, data.Base, data.Offset)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleLoadInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.LoadRegister(c.code, operands.Register, operands.Address.Base, operands.Address.Offset, operands.Address.Length)
|
||||
} else {
|
||||
c.code = x86.LoadDynamicRegister(c.code, operands.Register, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleStoreInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeMemoryNumber:
|
||||
operands := c.assembler.Param.MemoryNumber[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Number)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Number)
|
||||
}
|
||||
case asm.TypeMemoryLabel:
|
||||
operands := c.assembler.Param.MemoryLabel[instruction.Index]
|
||||
start := len(c.code)
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreNumber(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, 0b00_00_00_00)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicNumber(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, 0b00_00_00_00)
|
||||
}
|
||||
|
||||
size := 4
|
||||
opSize := len(c.code) - size - start
|
||||
|
||||
c.codePointers = append(c.codePointers, &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: uint8(opSize),
|
||||
Size: uint8(size),
|
||||
Resolve: func() Address {
|
||||
destination, exists := c.codeLabels[operands.Label.Name]
|
||||
|
||||
if !exists {
|
||||
panic("unknown label")
|
||||
}
|
||||
|
||||
return config.BaseAddress + c.codeStart + destination
|
||||
},
|
||||
})
|
||||
case asm.TypeMemoryRegister:
|
||||
operands := c.assembler.Param.MemoryRegister[instruction.Index]
|
||||
|
||||
if operands.Address.OffsetRegister < 0 {
|
||||
c.code = x86.StoreRegister(c.code, operands.Address.Base, operands.Address.Offset, operands.Address.Length, operands.Register)
|
||||
} else {
|
||||
c.code = x86.StoreDynamicRegister(c.code, operands.Address.Base, operands.Address.OffsetRegister, operands.Address.Length, operands.Register)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleAddInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.AddRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.AddRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleAndInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.AndRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.AndRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleDivInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Register)
|
||||
}
|
||||
|
||||
c.code = x86.MoveRegisterNumber(c.code, x86.TMP, operands.Number)
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, x86.TMP)
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Register, x86.RAX)
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, operands.Source)
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, x86.RAX)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleModuloInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
|
||||
if operands.Register != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Register)
|
||||
}
|
||||
|
||||
c.code = x86.MoveRegisterNumber(c.code, x86.TMP, operands.Number)
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, x86.TMP)
|
||||
|
||||
if operands.Register != x86.RDX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Register, x86.RDX)
|
||||
}
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
|
||||
if operands.Destination != x86.RAX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, x86.RAX, operands.Destination)
|
||||
}
|
||||
|
||||
c.code = x86.ExtendRAXToRDX(c.code)
|
||||
c.code = x86.DivRegister(c.code, operands.Source)
|
||||
|
||||
if operands.Destination != x86.RDX {
|
||||
c.code = x86.MoveRegisterRegister(c.code, operands.Destination, x86.RDX)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleMulInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.MulRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.MulRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleOrInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.OrRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.OrRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleSubInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.SubRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.SubRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleXorInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.XorRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.XorRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleNegateInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[instruction.Index]
|
||||
c.code = x86.NegateRegister(c.code, operands.Register)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handlePopInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[instruction.Index]
|
||||
c.code = x86.PopRegister(c.code, operands.Register)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handlePushInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeNumber:
|
||||
operands := c.assembler.Param.Number[instruction.Index]
|
||||
c.code = x86.PushNumber(c.code, int32(operands.Number))
|
||||
case asm.TypeRegister:
|
||||
operands := c.assembler.Param.Register[instruction.Index]
|
||||
c.code = x86.PushRegister(c.code, operands.Register)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleShiftLeftInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.ShiftLeftNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleShiftRightSignedInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.ShiftRightSignedNumber(c.code, operands.Register, byte(operands.Number)&0b111111)
|
||||
case asm.TypeRegisterRegister:
|
||||
panic("not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleCompareInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Type {
|
||||
case asm.TypeRegisterNumber:
|
||||
operands := c.assembler.Param.RegisterNumber[instruction.Index]
|
||||
c.code = x86.CompareRegisterNumber(c.code, operands.Register, operands.Number)
|
||||
case asm.TypeRegisterRegister:
|
||||
operands := c.assembler.Param.RegisterRegister[instruction.Index]
|
||||
c.code = x86.CompareRegisterRegister(c.code, operands.Destination, operands.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleDllCallInstruction(instruction asm.Instruction) {
|
||||
label := c.assembler.Param.Label[instruction.Index]
|
||||
c.code = x86.CallAt(c.code, 0x00_00_00_00)
|
||||
next := Address(len(c.code))
|
||||
position := next - 4
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(position),
|
||||
OpSize: 2,
|
||||
Size: 4,
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
dot := strings.Index(label.Name, ".")
|
||||
library := label.Name[:dot]
|
||||
funcName := label.Name[dot+1:]
|
||||
index := c.dlls.Index(library, funcName)
|
||||
|
||||
if index == -1 {
|
||||
panic("unknown DLL function " + label.Name)
|
||||
}
|
||||
|
||||
destination := c.importsStart + Address(index*8)
|
||||
from := c.codeStart + next
|
||||
return destination - from
|
||||
}
|
||||
|
||||
c.dllPointers = append(c.dllPointers, pointer)
|
||||
}
|
||||
|
||||
func (c *x86Compiler) handleJumpInstruction(instruction asm.Instruction) {
|
||||
switch instruction.Mnemonic {
|
||||
case asm.JE:
|
||||
c.code = x86.Jump8IfEqual(c.code, 0x00)
|
||||
case asm.JNE:
|
||||
c.code = x86.Jump8IfNotEqual(c.code, 0x00)
|
||||
case asm.JG:
|
||||
c.code = x86.Jump8IfGreater(c.code, 0x00)
|
||||
case asm.JGE:
|
||||
c.code = x86.Jump8IfGreaterOrEqual(c.code, 0x00)
|
||||
case asm.JL:
|
||||
c.code = x86.Jump8IfLess(c.code, 0x00)
|
||||
case asm.JLE:
|
||||
c.code = x86.Jump8IfLessOrEqual(c.code, 0x00)
|
||||
case asm.JUMP:
|
||||
c.code = x86.Jump8(c.code, 0x00)
|
||||
}
|
||||
|
||||
label := c.assembler.Param.Label[instruction.Index]
|
||||
size := 1
|
||||
|
||||
pointer := &pointer{
|
||||
Position: Address(len(c.code) - size),
|
||||
OpSize: 1,
|
||||
Size: uint8(size),
|
||||
}
|
||||
|
||||
pointer.Resolve = func() Address {
|
||||
destination, exists := c.codeLabels[label.Name]
|
||||
|
||||
if !exists {
|
||||
panic(fmt.Sprintf("unknown jump label %s", label.Name))
|
||||
}
|
||||
|
||||
distance := destination - (pointer.Position + Address(pointer.Size))
|
||||
return distance
|
||||
}
|
||||
|
||||
c.codePointers = append(c.codePointers, pointer)
|
||||
}
|
Reference in New Issue
Block a user