From cac2bad2fe5d7f303b2bb45730a436ec5d8ff0aa Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sun, 6 Apr 2025 20:37:26 +0200 Subject: [PATCH] Refactored assembly compilation --- src/asmc/ARM.go | 320 --------------------------- src/asmc/Finalize.go | 8 +- src/asmc/X86.go | 218 ------------------ src/asmc/armCompiler.go | 420 +++++++++++++++++++++++++++++++++++ src/asmc/call.go | 44 ---- src/asmc/dllCall.go | 38 ---- src/asmc/jumpARM.go | 52 ----- src/asmc/jumpX86.go | 49 ----- src/asmc/load.go | 19 -- src/asmc/move.go | 60 ----- src/asmc/store.go | 55 ----- src/asmc/x86Compiler.go | 474 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 900 insertions(+), 857 deletions(-) delete mode 100644 src/asmc/ARM.go delete mode 100644 src/asmc/X86.go create mode 100644 src/asmc/armCompiler.go delete mode 100644 src/asmc/call.go delete mode 100644 src/asmc/dllCall.go delete mode 100644 src/asmc/jumpARM.go delete mode 100644 src/asmc/jumpX86.go delete mode 100644 src/asmc/load.go delete mode 100644 src/asmc/move.go delete mode 100644 src/asmc/store.go create mode 100644 src/asmc/x86Compiler.go diff --git a/src/asmc/ARM.go b/src/asmc/ARM.go deleted file mode 100644 index 42ff3a6..0000000 --- a/src/asmc/ARM.go +++ /dev/null @@ -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) -} diff --git a/src/asmc/Finalize.go b/src/asmc/Finalize.go index ec9e678..93e04ab 100644 --- a/src/asmc/Finalize.go +++ b/src/asmc/Finalize.go @@ -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) } } diff --git a/src/asmc/X86.go b/src/asmc/X86.go deleted file mode 100644 index 5cdf60f..0000000 --- a/src/asmc/X86.go +++ /dev/null @@ -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()) - } -} diff --git a/src/asmc/armCompiler.go b/src/asmc/armCompiler.go new file mode 100644 index 0000000..6c11240 --- /dev/null +++ b/src/asmc/armCompiler.go @@ -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) +} diff --git a/src/asmc/call.go b/src/asmc/call.go deleted file mode 100644 index c941bb6..0000000 --- a/src/asmc/call.go +++ /dev/null @@ -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) - } -} diff --git a/src/asmc/dllCall.go b/src/asmc/dllCall.go deleted file mode 100644 index 203fbc1..0000000 --- a/src/asmc/dllCall.go +++ /dev/null @@ -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) -} diff --git a/src/asmc/jumpARM.go b/src/asmc/jumpARM.go deleted file mode 100644 index 81a96ee..0000000 --- a/src/asmc/jumpARM.go +++ /dev/null @@ -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) -} diff --git a/src/asmc/jumpX86.go b/src/asmc/jumpX86.go deleted file mode 100644 index e9ace20..0000000 --- a/src/asmc/jumpX86.go +++ /dev/null @@ -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) -} diff --git a/src/asmc/load.go b/src/asmc/load.go deleted file mode 100644 index 845092b..0000000 --- a/src/asmc/load.go +++ /dev/null @@ -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) - } - } -} diff --git a/src/asmc/move.go b/src/asmc/move.go deleted file mode 100644 index 3963ba5..0000000 --- a/src/asmc/move.go +++ /dev/null @@ -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 - }, - }) - } - } -} diff --git a/src/asmc/store.go b/src/asmc/store.go deleted file mode 100644 index 42352c4..0000000 --- a/src/asmc/store.go +++ /dev/null @@ -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) - } - } -} diff --git a/src/asmc/x86Compiler.go b/src/asmc/x86Compiler.go new file mode 100644 index 0000000..b721039 --- /dev/null +++ b/src/asmc/x86Compiler.go @@ -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) +}