Implemented an assembler
All checks were successful
/ test (push) Successful in 28s

This commit is contained in:
Eduard Urbach 2025-06-24 12:55:26 +02:00
parent 2b703e9af2
commit 70c2da4a4d
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
40 changed files with 821 additions and 117 deletions

78
src/asm/Assembler.go Normal file
View file

@ -0,0 +1,78 @@
package asm
import (
"maps"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/data"
"git.urbach.dev/cli/q/src/elf"
"git.urbach.dev/cli/q/src/exe"
)
// Assembler contains a list of instructions.
type Assembler struct {
Data data.Data
Instructions []Instruction
}
// Append adds another instruction.
func (a *Assembler) Append(instr Instruction) {
a.Instructions = append(a.Instructions, instr)
}
// Compile compiles the instructions to machine code.
func (a *Assembler) Compile(b *build.Build) (code []byte, data []byte) {
data, dataLabels := a.Data.Finalize()
c := compiler{
code: make([]byte, 0, len(a.Instructions)*8),
data: data,
dataLabels: dataLabels,
labels: make(map[string]Address, 32),
}
switch b.Arch {
case build.ARM:
armc := compilerARM{compiler: &c}
for _, instr := range a.Instructions {
armc.Compile(instr)
}
case build.X86:
x86c := compilerX86{compiler: &c}
for _, instr := range a.Instructions {
x86c.Compile(instr)
}
}
x := exe.New(elf.HeaderEnd, b.FileAlign, b.MemoryAlign)
x.InitSections(c.code, c.data)
dataSectionOffset := x.Sections[1].MemoryOffset - x.Sections[0].MemoryOffset
for dataLabel, address := range dataLabels {
c.labels[dataLabel] = dataSectionOffset + address
}
for _, call := range c.deferred {
call()
}
return c.code, c.data
}
// Merge combines the contents of this assembler with another one.
func (a *Assembler) Merge(b *Assembler) {
maps.Copy(a.Data, b.Data)
a.Instructions = append(a.Instructions, b.Instructions...)
}
// SetData sets the data for the given label.
func (a *Assembler) SetData(label string, bytes []byte) {
if a.Data == nil {
a.Data = data.Data{}
}
a.Data.Insert(label, bytes)
}