Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active April 24, 2023 03:13
Show Gist options
  • Save pervognsen/bb71bb110c0829b448cbaae64cbe671c to your computer and use it in GitHub Desktop.
Save pervognsen/bb71bb110c0829b448cbaae64cbe671c to your computer and use it in GitHub Desktop.
.code
; struct Xeno_Win64CallContext {
; void *function_pointer;
; uint64_t integer_return_value;
; uint64_t floating_point_return_value;
; uint64_t register_arguments[4];
; uint64_t *stack_arguments;
; size_t stack_arguments_count;
; };
Xeno_Win64CallContext struct
function_pointer QWORD ?
integer_return_value QWORD ?
floating_point_return_value QWORD ?
register_argument0 QWORD ?
register_argument1 QWORD ?
register_argument2 QWORD ?
register_argument3 QWORD ?
stack_arguments QWORD ?
stack_arguments_count QWORD ?
Xeno_Win64CallContext ends
; extern "C" void Xeno_Win64Call(Xeno_Win64CallContext *context);
Xeno_Win64Call proc frame
mov qword ptr [rsp + 8], rbx
.savereg rbx, 8
mov qword ptr [rsp + 16], rbp
.savereg rbp, 16
mov rbp, rsp
.setframe rbp, 0
.endprolog
mov rbx, rcx
mov rcx, (Xeno_Win64CallContext ptr [rbx]).register_argument0
movd xmm0, rcx
mov rdx, (Xeno_Win64CallContext ptr [rbx]).register_argument1
movd xmm1, rdx
mov r8, (Xeno_Win64CallContext ptr[rbx]).register_argument2
movd xmm2, r8
mov r9, (Xeno_Win64CallContext ptr [rbx]).register_argument3
movd xmm3, r9
mov r10, (Xeno_Win64CallContext ptr [rbx]).stack_arguments_count
lea r10, [8 * r10]
mov r11, (Xeno_Win64CallContext ptr [rbx]).stack_arguments
lea r11, [r11 + r10]
mov rax, rsp
sub rax, r10
and rax, 0FFFFFFFFFFFFFFF0h
lea rsp, [rax + r10]
cmp r10, 0
next:
jz done
sub r11, 8
push qword ptr [r11]
sub r10, 8
jmp next
done:
mov rax, (Xeno_Win64CallContext ptr [rbx]).function_pointer
sub rsp, 32
call rax
mov (Xeno_Win64CallContext ptr [rbx]).integer_return_value, rax
movd (Xeno_Win64CallContext ptr [rbx]).floating_point_return_value, xmm0
mov rsp, rbp
mov rbp, qword ptr [rsp + 16]
mov rbx, qword ptr [rsp + 8]
ret
Xeno_Win64Call endp
end
struct Xeno_Win64CallContext {
void *function_pointer;
uint64_t integer_return_value;
uint64_t floating_point_return_value;
uint64_t register_arguments[4];
uint64_t *stack_arguments;
size_t stack_arguments_count;
};
extern "C" void Xeno_Win64Call(Xeno_Win64CallContext *context);
void Xeno_Call(Xeno_Data function, Xeno_Data return_value_destination, Xeno_Data *arguments, size_t arguments_count) {
Assert(function.type->kind == XENO_FUNCTION);
Xeno_Function *function_type = function.type->function;
Assert(function_type->arguments_count == arguments_count);
Xeno_Win64CallContext win64_call_context;
size_t temporaries_size = 0;
for (size_t index = 0; index < function_type->arguments_count; index++) {
size_t size = function_type->argument_types[index]->size;
if (size > 8) {
temporaries_size += (size + 15) & ~15;
}
}
uint64_t *temporaries = 0;
if (temporaries_size > 0) {
temporaries = (uint64_t *)_alloca(temporaries_size + 15);
temporaries = (uint64_t *)(((uintptr_t)temporaries + 15) & ~15);
}
uint64_t *temporaries_pointer = temporaries;
size_t argument_register = 0;
size_t actual_arguments_count = function_type->arguments_count;
if (function_type->return_type->size > 8) {
Assert(function_type->return_type == return_value_destination.type);
win64_call_context.register_arguments[0] = (uint64_t)return_value_destination.pointer;
argument_register = 1;
actual_arguments_count++;
}
uint64_t *stack_arguments = 0;
if (actual_arguments_count > 4) {
stack_arguments = (uint64_t *)_alloca((actual_arguments_count - 4) * sizeof(uint64_t));
}
uint64_t *stack_argument = stack_arguments;
for (size_t i = 0; i < function_type->arguments_count; i++) {
Xeno_Type *argument_type = function_type->argument_types[i];
uint64_t argument;
if (argument_type->size <= 8) {
if (Xeno_IsPrimitiveType(argument_type)) {
Xeno_Data argument_data = {&argument, argument_type};
Xeno_Cast(argument_data, arguments[i]);
} else {
Assert(argument_type == arguments[i].type);
memcpy(&argument, arguments[i].pointer, argument_type->size);
}
} else {
Assert(argument_type == arguments[i].type);
memcpy(temporaries_pointer, arguments[i].pointer, argument_type->size);
argument = (uint64_t)temporaries_pointer;
temporaries_pointer += argument_type->size;
temporaries_pointer = (uint64_t *)(((uintptr_t)temporaries_pointer + 15) & ~15);
}
if (argument_register < 4) {
win64_call_context.register_arguments[argument_register] = argument;
argument_register++;
} else {
*stack_argument = argument;
stack_argument++;
}
}
win64_call_context.function_pointer = function.pointer;
win64_call_context.stack_arguments = stack_arguments;
win64_call_context.stack_arguments_count = stack_argument - stack_arguments;
Xeno_Win64Call(&win64_call_context);
if (function_type->return_type->size <= 8) {
uint64_t return_value;
if (function_type->return_type->kind == XENO_FLOAT || function_type->return_type->kind == XENO_DOUBLE) {
return_value = win64_call_context.floating_point_return_value;
} else {
return_value = win64_call_context.integer_return_value;
}
Xeno_Data return_value_data = {&return_value, function_type->return_type};
Xeno_Cast(return_value_destination, return_value_data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment