Refactored assembly compilation

This commit is contained in:
Eduard Urbach 2025-04-06 20:37:26 +02:00
parent 51fc0a1272
commit 1269a09049
Signed by: eduard
GPG key ID: 49226B848C78F6C8
12 changed files with 900 additions and 857 deletions

474
src/asmc/x86Compiler.go Normal file
View 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)
}