From 34aeba740a2ffb110c0bfd96e1ec88276d121f48 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 16 Aug 2024 20:39:04 +0200 Subject: [PATCH] Implemented indirect calls --- src/arch/x64/Call.go | 18 +++++++++++++++++- src/asm/Finalize.go | 19 +++++++++++++++++++ src/asm/Mnemonic.go | 3 +++ src/compiler/Result.go | 10 ++++++---- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/arch/x64/Call.go b/src/arch/x64/Call.go index 1bbfc46..6c37d7b 100644 --- a/src/arch/x64/Call.go +++ b/src/arch/x64/Call.go @@ -1,7 +1,8 @@ package x64 // Call places the return address on the top of the stack and continues -// program flow at the new address. The address is relative to the next instruction. +// program flow at the new address. +// The address is relative to the next instruction. func Call(code []byte, address uint32) []byte { return append( code, @@ -12,3 +13,18 @@ func Call(code []byte, address uint32) []byte { byte(address>>24), ) } + +// CallAtAddress places the return address on the top of the stack and +// continues program flow at the address stored at the given memory address. +// The memory address is relative to the next instruction. +func CallAtAddress(code []byte, address uint32) []byte { + return append( + code, + 0xFF, + 0x15, + byte(address), + byte(address>>8), + byte(address>>16), + byte(address>>24), + ) +} diff --git a/src/asm/Finalize.go b/src/asm/Finalize.go index 4276e38..b4f7b3c 100644 --- a/src/asm/Finalize.go +++ b/src/asm/Finalize.go @@ -111,6 +111,25 @@ func (a Assembler) Finalize() ([]byte, []byte) { codePointers = append(codePointers, pointer) + case CALL_AT: + code = x64.CallAtAddress(code, 0x00_00_00_00) + size := 4 + // label := x.Data.(*Label) + + pointer := &Pointer{ + Position: Address(len(code) - size), + OpSize: 2, + Size: uint8(size), + } + + pointer.Resolve = func() Address { + destination := Address(0x1038) + distance := destination - (pointer.Position + Address(pointer.Size)) + return Address(distance) + } + + codePointers = append(codePointers, pointer) + case COMMENT: continue diff --git a/src/asm/Mnemonic.go b/src/asm/Mnemonic.go index e8c778b..36687b7 100644 --- a/src/asm/Mnemonic.go +++ b/src/asm/Mnemonic.go @@ -29,6 +29,7 @@ const ( // Control flow CALL + CALL_AT JE JNE JG @@ -54,6 +55,8 @@ func (m Mnemonic) String() string { return "and" case CALL: return "call" + case CALL_AT: + return "call at" case COMMENT: return "comment" case COMPARE: diff --git a/src/compiler/Result.go b/src/compiler/Result.go index d9f7fcf..5ca790f 100644 --- a/src/compiler/Result.go +++ b/src/compiler/Result.go @@ -48,8 +48,9 @@ func (r *Result) finalize() ([]byte, []byte) { final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 0) final.Syscall() case "windows": - final.RegisterNumber(asm.MOVE, x64.RAX, 0) - final.Return() + final.RegisterNumber(asm.SUB, x64.RSP, 32+8) + final.RegisterNumber(asm.MOVE, x64.RCX, 0) + final.Label(asm.CALL_AT, "ExitProcess") } // This will place the main function immediately after the entry point @@ -70,8 +71,9 @@ func (r *Result) finalize() ([]byte, []byte) { final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 1) final.Syscall() case "windows": - final.RegisterNumber(asm.MOVE, x64.RAX, 1) - final.Return() + final.RegisterNumber(asm.SUB, x64.RSP, 32+8) + final.RegisterNumber(asm.MOVE, x64.RCX, 1) + final.Label(asm.CALL_AT, "ExitProcess") } code, data := final.Finalize()