Added basic support for arm64
This commit is contained in:
10
src/arm/Call.go
Normal file
10
src/arm/Call.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
// Call branches to a PC-relative offset, setting the register X30 to PC+4.
|
||||||
|
// The offset starts from the address of this instruction and is encoded as "imm26" times 4.
|
||||||
|
// This instruction is also known as BL (branch with link).
|
||||||
|
func Call(code []byte, offset uint32) []byte {
|
||||||
|
return binary.LittleEndian.AppendUint32(code, uint32(0b100101<<26)|offset)
|
||||||
|
}
|
29
src/arm/Move.go
Normal file
29
src/arm/Move.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MoveRegisterNumber moves an integer into the given register.
|
||||||
|
func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte {
|
||||||
|
return MoveZero(code, destination, 0, uint16(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveKeep moves a 16-bit integer into the given register and keeps all other bits.
|
||||||
|
func MoveKeep(code []byte, destination cpu.Register, halfword int, number uint16) []byte {
|
||||||
|
x := mov(0b11, halfword, number, destination)
|
||||||
|
return binary.LittleEndian.AppendUint32(code, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveZero moves a 16-bit integer into the given register and clears all other bits to zero.
|
||||||
|
func MoveZero(code []byte, destination cpu.Register, halfword int, number uint16) []byte {
|
||||||
|
x := mov(0b10, halfword, number, destination)
|
||||||
|
return binary.LittleEndian.AppendUint32(code, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mov encodes a generic move instruction.
|
||||||
|
func mov(opCode uint32, halfword int, number uint16, destination cpu.Register) uint32 {
|
||||||
|
return (1 << 31) | (opCode << 29) | (0b100101 << 23) | uint32(halfword<<21) | uint32(number<<5) | uint32(destination)
|
||||||
|
}
|
43
src/arm/Move_test.go
Normal file
43
src/arm/Move_test.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package arm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
|
"git.urbach.dev/go/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMoveKeep(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Register cpu.Register
|
||||||
|
Number uint16
|
||||||
|
Code []byte
|
||||||
|
}{
|
||||||
|
{arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xF2}},
|
||||||
|
{arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xF2}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("movk %s, %x", pattern.Register, pattern.Number)
|
||||||
|
code := arm.MoveKeep(nil, pattern.Register, 0, pattern.Number)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMoveZero(t *testing.T) {
|
||||||
|
usagePatterns := []struct {
|
||||||
|
Register cpu.Register
|
||||||
|
Number uint16
|
||||||
|
Code []byte
|
||||||
|
}{
|
||||||
|
{arm.X0, 0, []byte{0x00, 0x00, 0x80, 0xD2}},
|
||||||
|
{arm.X0, 1, []byte{0x20, 0x00, 0x80, 0xD2}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pattern := range usagePatterns {
|
||||||
|
t.Logf("movz %s, %x", pattern.Register, pattern.Number)
|
||||||
|
code := arm.MoveZero(nil, pattern.Register, 0, pattern.Number)
|
||||||
|
assert.DeepEqual(t, code, pattern.Code)
|
||||||
|
}
|
||||||
|
}
|
6
src/arm/Nop.go
Normal file
6
src/arm/Nop.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
// Nop does nothing. This can be used for alignment purposes.
|
||||||
|
func Nop(code []byte) []byte {
|
||||||
|
return append(code, 0x1F, 0x20, 0x03, 0xD5)
|
||||||
|
}
|
@ -38,7 +38,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
GeneralRegisters = []cpu.Register{X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28}
|
||||||
|
InputRegisters = SyscallInputRegisters
|
||||||
|
OutputRegisters = SyscallInputRegisters
|
||||||
SyscallInputRegisters = []cpu.Register{X8, X0, X1, X2, X3, X4, X5}
|
SyscallInputRegisters = []cpu.Register{X8, X0, X1, X2, X3, X4, X5}
|
||||||
|
SyscallOutputRegisters = []cpu.Register{X0, X1}
|
||||||
WindowsInputRegisters = []cpu.Register{X0, X1, X2, X3, X4, X5, X6, X7}
|
WindowsInputRegisters = []cpu.Register{X0, X1, X2, X3, X4, X5, X6, X7}
|
||||||
WindowsOutputRegisters = []cpu.Register{X0, X1}
|
WindowsOutputRegisters = []cpu.Register{X0, X1}
|
||||||
|
|
||||||
|
CPU = cpu.CPU{
|
||||||
|
General: GeneralRegisters,
|
||||||
|
Input: InputRegisters,
|
||||||
|
Output: OutputRegisters,
|
||||||
|
SyscallInput: SyscallInputRegisters,
|
||||||
|
SyscallOutput: SyscallOutputRegisters,
|
||||||
|
NumRegisters: 32,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
6
src/arm/Return.go
Normal file
6
src/arm/Return.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
// Return transfers program control to the caller.
|
||||||
|
func Return(code []byte) []byte {
|
||||||
|
return append(code, 0xC0, 0x03, 0x5F, 0xD6)
|
||||||
|
}
|
6
src/arm/Syscall.go
Normal file
6
src/arm/Syscall.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package arm
|
||||||
|
|
||||||
|
// Syscall is the primary way to communicate with the OS kernel.
|
||||||
|
func Syscall(code []byte) []byte {
|
||||||
|
return append(code, 0x01, 0x00, 0x00, 0xD4)
|
||||||
|
}
|
16
src/arm/arm_test.go
Normal file
16
src/arm/arm_test.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package arm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/go/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestARM(t *testing.T) {
|
||||||
|
assert.DeepEqual(t, arm.Call(nil, 0), []byte{0x00, 0x00, 0x00, 0x94})
|
||||||
|
assert.DeepEqual(t, arm.MoveRegisterNumber(nil, arm.X0, 42), arm.MoveZero(nil, arm.X0, 0, 42))
|
||||||
|
assert.DeepEqual(t, arm.Nop(nil), []byte{0x1F, 0x20, 0x03, 0xD5})
|
||||||
|
assert.DeepEqual(t, arm.Return(nil), []byte{0xC0, 0x03, 0x5F, 0xD6})
|
||||||
|
assert.DeepEqual(t, arm.Syscall(nil), []byte{0x01, 0x00, 0x00, 0xD4})
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package asmc
|
package asmc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
"git.urbach.dev/cli/q/src/asm"
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
"git.urbach.dev/cli/q/src/config"
|
"git.urbach.dev/cli/q/src/config"
|
||||||
"git.urbach.dev/cli/q/src/dll"
|
"git.urbach.dev/cli/q/src/dll"
|
||||||
@ -24,8 +25,20 @@ func Finalize(a asm.Assembler, dlls dll.List) ([]byte, []byte) {
|
|||||||
dlls: dlls,
|
dlls: dlls,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch config.TargetArch {
|
||||||
|
case config.ARM:
|
||||||
for _, x := range a.Instructions {
|
for _, x := range a.Instructions {
|
||||||
c.compile(x)
|
c.compileARM(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.code = arm.MoveRegisterNumber(c.code, arm.X0, 0)
|
||||||
|
c.code = arm.MoveRegisterNumber(c.code, arm.X8, 0x5D)
|
||||||
|
c.code = arm.Syscall(c.code)
|
||||||
|
|
||||||
|
case config.X86:
|
||||||
|
for _, x := range a.Instructions {
|
||||||
|
c.compileX86(x)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.resolvePointers()
|
c.resolvePointers()
|
||||||
|
25
src/asmc/compileARM.go
Normal file
25
src/asmc/compileARM.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package asmc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *compiler) compileARM(x asm.Instruction) {
|
||||||
|
switch x.Mnemonic {
|
||||||
|
// case asm.MOVE:
|
||||||
|
// switch operands := x.Data.(type) {
|
||||||
|
// case *asm.RegisterNumber:
|
||||||
|
// c.code = arm.MoveRegisterNumber(c.code, operands.Register, operands.Number)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// case asm.RETURN:
|
||||||
|
// c.code = arm.Return(c.code)
|
||||||
|
|
||||||
|
// case asm.SYSCALL:
|
||||||
|
// c.code = arm.Syscall(c.code)
|
||||||
|
|
||||||
|
default:
|
||||||
|
c.code = arm.Nop(c.code)
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import (
|
|||||||
"git.urbach.dev/cli/q/src/x86"
|
"git.urbach.dev/cli/q/src/x86"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *compiler) compile(x asm.Instruction) {
|
func (c *compiler) compileX86(x asm.Instruction) {
|
||||||
switch x.Mnemonic {
|
switch x.Mnemonic {
|
||||||
case asm.ADD:
|
case asm.ADD:
|
||||||
switch operands := x.Data.(type) {
|
switch operands := x.Data.(type) {
|
@ -48,7 +48,14 @@ func buildExecutable(args []string) (*build.Build, error) {
|
|||||||
return b, &ExpectedParameterError{Parameter: "arch"}
|
return b, &ExpectedParameterError{Parameter: "arch"}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.TargetArch = args[i]
|
switch args[i] {
|
||||||
|
case "arm":
|
||||||
|
config.TargetArch = config.ARM
|
||||||
|
case "x86":
|
||||||
|
config.TargetArch = config.X86
|
||||||
|
default:
|
||||||
|
return b, &InvalidValueError{Value: args[i], Parameter: "arch"}
|
||||||
|
}
|
||||||
|
|
||||||
case "--os":
|
case "--os":
|
||||||
i++
|
i++
|
||||||
@ -77,7 +84,7 @@ func buildExecutable(args []string) (*build.Build, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TargetOS == config.Unknown {
|
if config.TargetOS == config.UnknownOS {
|
||||||
return b, &InvalidValueError{Value: runtime.GOOS, Parameter: "os"}
|
return b, &InvalidValueError{Value: runtime.GOOS, Parameter: "os"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ func Help(w io.Writer, code int) int {
|
|||||||
Commands:
|
Commands:
|
||||||
|
|
||||||
build [directory | file] build an executable from a file or directory
|
build [directory | file] build an executable from a file or directory
|
||||||
--arch [arch] cross-compile for another CPU architecture [x86|arm|riscv]
|
--arch [arch] cross-compile for another CPU architecture [x86|arm]
|
||||||
--assembly, -a show assembly instructions
|
--assembly, -a show assembly instructions
|
||||||
--dry, -d skip writing the executable to disk
|
--dry, -d skip writing the executable to disk
|
||||||
--os [os] cross-compile for another OS [linux|mac|windows]
|
--os [os] cross-compile for another OS [linux|mac|windows]
|
||||||
|
9
src/config/arch.go
Normal file
9
src/config/arch.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type Arch uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnknownArch Arch = iota
|
||||||
|
ARM
|
||||||
|
X86
|
||||||
|
)
|
@ -7,7 +7,7 @@ var (
|
|||||||
Dry bool // Skips writing the executable to disk.
|
Dry bool // Skips writing the executable to disk.
|
||||||
ShowAssembly bool // Shows assembly instructions at the end.
|
ShowAssembly bool // Shows assembly instructions at the end.
|
||||||
ShowStatistics bool // Shows statistics at the end.
|
ShowStatistics bool // Shows statistics at the end.
|
||||||
TargetArch string // Target architecture.
|
TargetArch Arch // Target architecture.
|
||||||
TargetOS OS // Target platform.
|
TargetOS OS // Target platform.
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,7 +16,15 @@ func Reset() {
|
|||||||
ShowAssembly = false
|
ShowAssembly = false
|
||||||
ShowStatistics = false
|
ShowStatistics = false
|
||||||
Dry = false
|
Dry = false
|
||||||
TargetArch = runtime.GOARCH
|
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
TargetArch = X86
|
||||||
|
case "arm":
|
||||||
|
TargetArch = ARM
|
||||||
|
default:
|
||||||
|
TargetArch = UnknownArch
|
||||||
|
}
|
||||||
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "linux":
|
case "linux":
|
||||||
@ -26,7 +34,7 @@ func Reset() {
|
|||||||
case "windows":
|
case "windows":
|
||||||
TargetOS = Windows
|
TargetOS = Windows
|
||||||
default:
|
default:
|
||||||
TargetOS = Unknown
|
TargetOS = UnknownOS
|
||||||
}
|
}
|
||||||
|
|
||||||
Optimize(true)
|
Optimize(true)
|
||||||
|
@ -3,7 +3,7 @@ package config
|
|||||||
type OS uint8
|
type OS uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Unknown OS = iota
|
UnknownOS OS = iota
|
||||||
Linux
|
Linux
|
||||||
Mac
|
Mac
|
||||||
Windows
|
Windows
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/arm"
|
||||||
"git.urbach.dev/cli/q/src/asm"
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
|
"git.urbach.dev/cli/q/src/config"
|
||||||
"git.urbach.dev/cli/q/src/cpu"
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
"git.urbach.dev/cli/q/src/fs"
|
"git.urbach.dev/cli/q/src/fs"
|
||||||
"git.urbach.dev/cli/q/src/register"
|
"git.urbach.dev/cli/q/src/register"
|
||||||
@ -11,6 +13,15 @@ import (
|
|||||||
|
|
||||||
// NewFunction creates a new function.
|
// NewFunction creates a new function.
|
||||||
func NewFunction(pkg string, name string, file *fs.File) *Function {
|
func NewFunction(pkg string, name string, file *fs.File) *Function {
|
||||||
|
var cpu *cpu.CPU
|
||||||
|
|
||||||
|
switch config.TargetArch {
|
||||||
|
case config.ARM:
|
||||||
|
cpu = &arm.CPU
|
||||||
|
case config.X86:
|
||||||
|
cpu = &x86.CPU
|
||||||
|
}
|
||||||
|
|
||||||
return &Function{
|
return &Function{
|
||||||
Package: pkg,
|
Package: pkg,
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -23,14 +34,7 @@ func NewFunction(pkg string, name string, file *fs.File) *Function {
|
|||||||
Stack: scope.Stack{
|
Stack: scope.Stack{
|
||||||
Scopes: []*scope.Scope{{}},
|
Scopes: []*scope.Scope{{}},
|
||||||
},
|
},
|
||||||
CPU: cpu.CPU{
|
CPU: cpu,
|
||||||
General: x86.GeneralRegisters,
|
|
||||||
Input: x86.InputRegisters,
|
|
||||||
Output: x86.OutputRegisters,
|
|
||||||
SyscallInput: x86.SyscallInputRegisters,
|
|
||||||
SyscallOutput: x86.SyscallOutputRegisters,
|
|
||||||
NumRegisters: 16,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ const (
|
|||||||
LittleEndian = 1
|
LittleEndian = 1
|
||||||
TypeExecutable = 2
|
TypeExecutable = 2
|
||||||
ArchitectureAMD64 = 0x3E
|
ArchitectureAMD64 = 0x3E
|
||||||
|
ArchitectureARM64 = 0xB7
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProgramType int32
|
type ProgramType int32
|
||||||
|
@ -23,8 +23,16 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
var (
|
var (
|
||||||
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
|
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
|
||||||
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
|
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
|
||||||
|
arch int16
|
||||||
)
|
)
|
||||||
|
|
||||||
|
switch config.TargetArch {
|
||||||
|
case config.ARM:
|
||||||
|
arch = ArchitectureARM64
|
||||||
|
case config.X86:
|
||||||
|
arch = ArchitectureAMD64
|
||||||
|
}
|
||||||
|
|
||||||
elf := &ELF{
|
elf := &ELF{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
||||||
@ -34,7 +42,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
OSABI: 0,
|
OSABI: 0,
|
||||||
ABIVersion: 0,
|
ABIVersion: 0,
|
||||||
Type: TypeExecutable,
|
Type: TypeExecutable,
|
||||||
Architecture: ArchitectureAMD64,
|
Architecture: arch,
|
||||||
FileVersion: 1,
|
FileVersion: 1,
|
||||||
EntryPointInMemory: int64(config.BaseAddress + codeStart),
|
EntryPointInMemory: int64(config.BaseAddress + codeStart),
|
||||||
ProgramHeaderOffset: HeaderSize,
|
ProgramHeaderOffset: HeaderSize,
|
||||||
|
@ -9,6 +9,11 @@ const (
|
|||||||
CPU_ARM_64 CPU = CPU_ARM | 0x01000000
|
CPU_ARM_64 CPU = CPU_ARM | 0x01000000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CPU_SUBTYPE_ARM64_ALL = 0
|
||||||
|
CPU_SUBTYPE_X86_64_ALL = 3
|
||||||
|
)
|
||||||
|
|
||||||
type Prot uint32
|
type Prot uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -28,13 +28,24 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
var (
|
var (
|
||||||
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
|
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
|
||||||
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
|
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
|
||||||
|
arch CPU
|
||||||
|
microArch uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
switch config.TargetArch {
|
||||||
|
case config.ARM:
|
||||||
|
arch = CPU_ARM_64
|
||||||
|
microArch = CPU_SUBTYPE_ARM64_ALL | 0x80000000
|
||||||
|
case config.X86:
|
||||||
|
arch = CPU_X86_64
|
||||||
|
microArch = CPU_SUBTYPE_X86_64_ALL | 0x80000000
|
||||||
|
}
|
||||||
|
|
||||||
m := &MachO{
|
m := &MachO{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
Magic: 0xFEEDFACF,
|
Magic: 0xFEEDFACF,
|
||||||
Architecture: CPU_X86_64,
|
Architecture: arch,
|
||||||
MicroArchitecture: 3 | 0x80000000,
|
MicroArchitecture: microArch,
|
||||||
Type: TypeExecute,
|
Type: TypeExecute,
|
||||||
NumCommands: 4,
|
NumCommands: 4,
|
||||||
SizeCommands: SizeCommands,
|
SizeCommands: SizeCommands,
|
||||||
|
@ -35,12 +35,20 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
|
|||||||
importDirectorySize = DLLImportSize * len(dllImports)
|
importDirectorySize = DLLImportSize * len(dllImports)
|
||||||
importSectionSize = len(imports)*8 + len(dllData) + importDirectorySize
|
importSectionSize = len(imports)*8 + len(dllData) + importDirectorySize
|
||||||
imageSize, _ = fs.Align(importsStart+importSectionSize, config.Align)
|
imageSize, _ = fs.Align(importsStart+importSectionSize, config.Align)
|
||||||
|
arch uint16
|
||||||
)
|
)
|
||||||
|
|
||||||
if dlls.Contains("user32") {
|
if dlls.Contains("user32") {
|
||||||
subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch config.TargetArch {
|
||||||
|
case config.ARM:
|
||||||
|
arch = IMAGE_FILE_MACHINE_ARM64
|
||||||
|
case config.X86:
|
||||||
|
arch = IMAGE_FILE_MACHINE_AMD64
|
||||||
|
}
|
||||||
|
|
||||||
pe := &EXE{
|
pe := &EXE{
|
||||||
DOSHeader: DOSHeader{
|
DOSHeader: DOSHeader{
|
||||||
Magic: [4]byte{'M', 'Z', 0, 0},
|
Magic: [4]byte{'M', 'Z', 0, 0},
|
||||||
@ -48,7 +56,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
|
|||||||
},
|
},
|
||||||
NTHeader: NTHeader{
|
NTHeader: NTHeader{
|
||||||
Signature: [4]byte{'P', 'E', 0, 0},
|
Signature: [4]byte{'P', 'E', 0, 0},
|
||||||
Machine: IMAGE_FILE_MACHINE_AMD64,
|
Machine: arch,
|
||||||
NumberOfSections: uint16(NumSections),
|
NumberOfSections: uint16(NumSections),
|
||||||
TimeDateStamp: 0,
|
TimeDateStamp: 0,
|
||||||
PointerToSymbolTable: 0,
|
PointerToSymbolTable: 0,
|
||||||
|
@ -10,6 +10,6 @@ import (
|
|||||||
type Machine struct {
|
type Machine struct {
|
||||||
scope.Stack
|
scope.Stack
|
||||||
Assembler asm.Assembler
|
Assembler asm.Assembler
|
||||||
CPU cpu.CPU
|
CPU *cpu.CPU
|
||||||
RegisterHistory []uint64
|
RegisterHistory []uint64
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@ import "git.urbach.dev/cli/q/src/cpu"
|
|||||||
// Call places the return address on the top of the stack and continues
|
// Call places the return address on the top of the stack and continues
|
||||||
// program flow at the new address.
|
// program flow at the new address.
|
||||||
// The address is relative to the next instruction.
|
// The address is relative to the next instruction.
|
||||||
func Call(code []byte, address uint32) []byte {
|
func Call(code []byte, offset uint32) []byte {
|
||||||
return append(
|
return append(
|
||||||
code,
|
code,
|
||||||
0xE8,
|
0xE8,
|
||||||
byte(address),
|
byte(offset),
|
||||||
byte(address>>8),
|
byte(offset>>8),
|
||||||
byte(address>>16),
|
byte(offset>>16),
|
||||||
byte(address>>24),
|
byte(offset>>24),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,4 +30,13 @@ var (
|
|||||||
WindowsInputRegisters = []cpu.Register{RCX, RDX, R8, R9}
|
WindowsInputRegisters = []cpu.Register{RCX, RDX, R8, R9}
|
||||||
WindowsOutputRegisters = []cpu.Register{RAX}
|
WindowsOutputRegisters = []cpu.Register{RAX}
|
||||||
WindowsVolatileRegisters = []cpu.Register{RCX, RDX, R8, R9, R10, R11}
|
WindowsVolatileRegisters = []cpu.Register{RCX, RDX, R8, R9, R10, R11}
|
||||||
|
|
||||||
|
CPU = cpu.CPU{
|
||||||
|
General: GeneralRegisters,
|
||||||
|
Input: InputRegisters,
|
||||||
|
Output: OutputRegisters,
|
||||||
|
SyscallInput: SyscallInputRegisters,
|
||||||
|
SyscallOutput: SyscallOutputRegisters,
|
||||||
|
NumRegisters: 16,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user