Implemented function calls
This commit is contained in:
parent
cd1fe5eebb
commit
6043baee48
11 changed files with 114 additions and 62 deletions
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/binary"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/arch/x64"
|
||||
"git.akyoto.dev/cli/q/src/build/config"
|
||||
)
|
||||
|
||||
// Assembler contains a list of instructions.
|
||||
|
@ -23,19 +22,14 @@ func New() *Assembler {
|
|||
func (a *Assembler) Finalize() ([]byte, []byte) {
|
||||
code := make([]byte, 0, len(a.Instructions)*8)
|
||||
data := make([]byte, 0, 16)
|
||||
labels := map[string]Address{}
|
||||
pointers := []Pointer{}
|
||||
|
||||
for _, x := range a.Instructions {
|
||||
switch x.Mnemonic {
|
||||
case MOVE:
|
||||
code = x64.MoveRegNum32(code, uint8(x.Data.(*RegisterNumber).Register), uint32(x.Data.(*RegisterNumber).Number))
|
||||
|
||||
if x.Data.(*RegisterNumber).IsPointer {
|
||||
pointers = append(pointers, Pointer{
|
||||
Position: Address(len(code) - 4),
|
||||
Address: Address(x.Data.(*RegisterNumber).Number),
|
||||
})
|
||||
}
|
||||
regNum := x.Data.(*RegisterNumber)
|
||||
code = x64.MoveRegNum32(code, uint8(regNum.Register), uint32(regNum.Number))
|
||||
|
||||
case RETURN:
|
||||
code = x64.Return(code)
|
||||
|
@ -43,17 +37,33 @@ func (a *Assembler) Finalize() ([]byte, []byte) {
|
|||
case SYSCALL:
|
||||
code = x64.Syscall(code)
|
||||
|
||||
case CALL:
|
||||
code = x64.Call(code, 0x00_00_00_00)
|
||||
label := x.Data.(*Label)
|
||||
nextInstructionAddress := len(code)
|
||||
|
||||
pointers = append(pointers, Pointer{
|
||||
Position: Address(len(code) - 4),
|
||||
Resolve: func() Address {
|
||||
destination := labels[label.Name]
|
||||
distance := int32(destination) - int32(nextInstructionAddress)
|
||||
return Address(distance)
|
||||
},
|
||||
})
|
||||
|
||||
case LABEL:
|
||||
labels[x.Data.(*Label).Name] = Address(len(code))
|
||||
|
||||
default:
|
||||
panic("Unknown mnemonic: " + x.Mnemonic.String())
|
||||
}
|
||||
}
|
||||
|
||||
dataStart := config.BaseAddress + config.CodeOffset + Address(len(code))
|
||||
// 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)
|
||||
binary.LittleEndian.PutUint32(slice, pointer.Resolve())
|
||||
}
|
||||
|
||||
return code, data
|
||||
|
|
|
@ -7,21 +7,28 @@ func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) {
|
|||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: MOVE,
|
||||
Data: &RegisterNumber{
|
||||
Register: reg,
|
||||
Number: number,
|
||||
IsPointer: false,
|
||||
Register: reg,
|
||||
Number: number,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// MoveRegisterAddress moves an address into the given register.
|
||||
func (a *Assembler) MoveRegisterAddress(reg cpu.Register, address Address) {
|
||||
// Label adds a label at the current position.
|
||||
func (a *Assembler) Label(name string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: MOVE,
|
||||
Data: &RegisterNumber{
|
||||
Register: reg,
|
||||
Number: uint64(address),
|
||||
IsPointer: true,
|
||||
Mnemonic: LABEL,
|
||||
Data: &Label{
|
||||
Name: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Call calls a function whose position is identified by a label.
|
||||
func (a *Assembler) Call(name string) {
|
||||
a.Instructions = append(a.Instructions, Instruction{
|
||||
Mnemonic: CALL,
|
||||
Data: &Label{
|
||||
Name: name,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
11
src/build/asm/Label.go
Normal file
11
src/build/asm/Label.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package asm
|
||||
|
||||
// Label represents a jump label.
|
||||
type Label struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// String returns a human readable version.
|
||||
func (data *Label) String() string {
|
||||
return data.Name
|
||||
}
|
|
@ -7,6 +7,8 @@ const (
|
|||
MOVE
|
||||
RETURN
|
||||
SYSCALL
|
||||
LABEL
|
||||
CALL
|
||||
)
|
||||
|
||||
// String returns a human readable version.
|
||||
|
@ -20,6 +22,12 @@ func (m Mnemonic) String() string {
|
|||
|
||||
case SYSCALL:
|
||||
return "syscall"
|
||||
|
||||
case LABEL:
|
||||
return "label"
|
||||
|
||||
case CALL:
|
||||
return "call"
|
||||
}
|
||||
|
||||
return "NONE"
|
||||
|
|
|
@ -5,8 +5,8 @@ type Address = uint32
|
|||
|
||||
// Pointer stores a relative memory address that we can later turn into an absolute one.
|
||||
// Position: The machine code offset where the address was inserted.
|
||||
// Address: The offset inside the section.
|
||||
// Resolve: The function that will return the final address.
|
||||
type Pointer struct {
|
||||
Position uint32
|
||||
Address uint32
|
||||
Position Address
|
||||
Resolve func() Address
|
||||
}
|
||||
|
|
|
@ -8,9 +8,8 @@ import (
|
|||
|
||||
// RegisterNumber operates with a register and a number.
|
||||
type RegisterNumber struct {
|
||||
Register cpu.Register
|
||||
Number uint64
|
||||
IsPointer bool
|
||||
Register cpu.Register
|
||||
Number uint64
|
||||
}
|
||||
|
||||
// String returns a human readable version.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue