Improved Windows DLL calls

This commit is contained in:
Eduard Urbach 2024-08-19 11:11:45 +02:00
parent fa1dce31f3
commit ed6cee0acc
Signed by: eduard
GPG key ID: 49226B848C78F6C8
12 changed files with 124 additions and 68 deletions

View file

@ -10,6 +10,7 @@ import (
"git.akyoto.dev/cli/q/src/asm"
"git.akyoto.dev/cli/q/src/config"
"git.akyoto.dev/cli/q/src/core"
"git.akyoto.dev/cli/q/src/dll"
"git.akyoto.dev/cli/q/src/exe/elf"
"git.akyoto.dev/cli/q/src/exe/macho"
"git.akyoto.dev/cli/q/src/exe/pe"
@ -27,7 +28,7 @@ type Result struct {
}
// finalize generates the final machine code.
func (r *Result) finalize() ([]byte, []byte) {
func (r *Result) finalize() ([]byte, []byte, dll.List) {
// This will be the entry point of the executable.
// The only job of the entry function is to call `main` and exit cleanly.
// The reason we call `main` instead of using `main` itself is to place
@ -49,15 +50,22 @@ func (r *Result) finalize() ([]byte, []byte) {
final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 0)
final.Syscall()
case "windows":
final.RegisterNumber(asm.SUB, x64.RSP, 32+8)
final.RegisterNumber(asm.MOVE, x64.RCX, 0)
final.Label(asm.CALL_AT, "ExitProcess")
final.RegisterNumber(asm.MOVE, windows.X64InputRegisters[0], 0)
final.DLLCall("kernel32.ExitProcess")
}
dlls := dll.List{}
// This will place the main function immediately after the entry point
// and also add everything the main function calls recursively.
r.eachFunction(r.Main, map[*core.Function]bool{}, func(f *core.Function) {
final.Merge(f.Assembler)
for _, library := range f.DLLs {
for _, fn := range library.Functions {
dlls = dlls.Append(library.Name, fn)
}
}
})
final.Label(asm.LABEL, "_crash")
@ -72,13 +80,12 @@ func (r *Result) finalize() ([]byte, []byte) {
final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 1)
final.Syscall()
case "windows":
final.RegisterNumber(asm.SUB, x64.RSP, 32+8)
final.RegisterNumber(asm.MOVE, windows.X64InputRegisters[0], 1)
final.Label(asm.CALL_AT, "ExitProcess")
final.Label(asm.DLLCALL, "kernel32.ExitProcess")
}
code, data := final.Finalize(windows.DLLs)
return code, data
code, data := final.Finalize(dlls)
return code, data, dlls
}
// eachFunction recursively finds all the calls to external functions.
@ -116,8 +123,8 @@ func (r *Result) PrintInstructions() {
// Write writes the executable to the given writer.
func (r *Result) Write(writer io.Writer) error {
code, data := r.finalize()
return write(writer, code, data)
code, data, dlls := r.finalize()
return write(writer, code, data, dlls)
}
// Write writes an executable file to disk.
@ -145,7 +152,7 @@ func (r *Result) WriteFile(path string) error {
}
// write writes an executable file to the given writer.
func write(writer io.Writer, code []byte, data []byte) error {
func write(writer io.Writer, code []byte, data []byte, dlls dll.List) error {
buffer := bufio.NewWriter(writer)
switch config.TargetOS {
@ -154,7 +161,7 @@ func write(writer io.Writer, code []byte, data []byte) error {
case "mac":
macho.Write(buffer, code, data)
case "windows":
pe.Write(buffer, code, data, windows.DLLs)
pe.Write(buffer, code, data, dlls)
default:
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
}