package asm import ( "encoding/binary" "git.akyoto.dev/cli/q/src/arch/x64" "git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/log" "git.akyoto.dev/cli/q/src/register" ) // Assembler contains a list of instructions. type Assembler struct { Instructions []Instruction } // New creates a new assembler. func New() *Assembler { return &Assembler{ Instructions: make([]Instruction, 0, 8), } } // Finalize generates the final machine code. func (a *Assembler) Finalize() ([]byte, []byte) { code := make([]byte, 0, len(a.Instructions)*8) data := make(Data, 0, 16) pointers := []Pointer{} for _, x := range a.Instructions { switch x.Mnemonic { case MOV: code = x64.MoveRegNum32(code, uint8(x.Destination), uint32(x.Number)) case MOVDATA: code = x64.MoveRegNum32(code, uint8(x.Destination), 0) pointers = append(pointers, Pointer{ Position: Address(len(code) - 4), Address: data.Add(x.Data), }) case SYSCALL: code = x64.Syscall(code) } } if config.Verbose { for _, x := range a.Instructions { log.Info.Println(x.String()) } } dataStart := config.BaseAddress + config.CodeOffset + Address(len(code)) for _, pointer := range pointers { slice := code[pointer.Position : pointer.Position+4] address := dataStart + pointer.Address binary.LittleEndian.PutUint32(slice, address) } return code, data } // Merge combines the contents of this assembler with another one. func (a *Assembler) Merge(b *Assembler) { a.Instructions = append(a.Instructions, b.Instructions...) } // MoveRegisterData moves a data section address into the given register. func (a *Assembler) MoveRegisterData(reg register.ID, data []byte) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: MOVDATA, Destination: reg, Data: data, }) } // MoveRegisterNumber moves a number into the given register. func (a *Assembler) MoveRegisterNumber(reg register.ID, number uint64) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: MOV, Destination: reg, Number: number, }) } // Syscall executes a kernel function. func (a *Assembler) Syscall() { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: SYSCALL, }) }