mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-08 13:00:18 +02:00
353 lines
13 KiB
C++
353 lines
13 KiB
C++
/*
|
|
$info$
|
|
tags: thunklibs|X11
|
|
desc: Handles callbacks and varargs
|
|
$end_info$
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <stdio.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xlibint.h>
|
|
#undef min
|
|
#undef max
|
|
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xresource.h>
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <X11/extensions/XKBstr.h>
|
|
|
|
#include "common/Host.h"
|
|
#include <dlfcn.h>
|
|
#include <utility>
|
|
|
|
#include "thunkgen_host_libX11.inl"
|
|
|
|
#ifdef _M_ARM_64
|
|
// This Variadic asm only works for one signature
|
|
// ({uint32_t,uint64_t} a_0, size_t count, uint64_t *list)
|
|
//
|
|
// Variadic ABI for AArch64 (flat uint64_t):
|
|
// Arguments 0-7 is in registers
|
|
// 8+ stored on to stack
|
|
//
|
|
// The X11 functions we are calling need an additional nullptr passed in.
|
|
// nullptr will be at the end of the list of generated stack items when called through this.
|
|
// We will always generate a variadic frame of `count` objects + 1 for nullptr.
|
|
//
|
|
// Incoming:
|
|
// x0 = XIM
|
|
// x1 = count
|
|
// x2 = array of 64-bit values
|
|
// x3 = Function to call
|
|
//
|
|
// Outgoing:
|
|
// x0: Ptr
|
|
|
|
__attribute__((naked))
|
|
void *libX11_Variadic_u64(uint64_t a_0, size_t count, unsigned long *list, void *Func) {
|
|
asm volatile(R"(
|
|
# Move our function to x8, which will be unused
|
|
mov x8, x3
|
|
|
|
# Move our list to x9, which will be unused
|
|
mov x9, x2
|
|
|
|
# >6 means use stack callback
|
|
cmp x1, 6
|
|
b.gt .stack%=
|
|
|
|
# Setup a jump table
|
|
adr x10, .zero%=
|
|
adr x11, .jump_table%=
|
|
ldrb w11, [x11, x1]
|
|
add x10, x10, x11, lsl 2
|
|
br x10
|
|
|
|
.zero%=:
|
|
mov x1, 0
|
|
br x8
|
|
|
|
.one%=:
|
|
ldr x1, [x9, 0]
|
|
mov x2, #0
|
|
br x8
|
|
|
|
.two%=:
|
|
ldp x1, x2, [x9, 0]
|
|
mov x3, 0
|
|
br x8
|
|
|
|
.three%=:
|
|
ldp x1, x2, [x9, 0]
|
|
ldr x3, [x9, 16]
|
|
mov x4, 0
|
|
br x8
|
|
|
|
.four%=:
|
|
ldp x1, x2, [x9, 0]
|
|
ldp x3, x4, [x9, 16]
|
|
mov x5, 0
|
|
br x8
|
|
|
|
.five%=:
|
|
ldp x1, x2, [x9, 0]
|
|
ldp x3, x4, [x9, 16]
|
|
ldr x5, [x9, 32]
|
|
mov x6, 0
|
|
br x8
|
|
|
|
.six%=:
|
|
ldp x1, x2, [x9, 0]
|
|
ldp x3, x4, [x9, 16]
|
|
ldp x5, x6, [x9, 32]
|
|
mov x7, 0
|
|
br x8
|
|
|
|
.stack%=:
|
|
# Store LR and x28
|
|
stp x28, x30, [sp, -16]!
|
|
|
|
# x8 = <arg ptr>
|
|
# x0 = <arg im>
|
|
# x1 = <count>
|
|
# x9 = <list ptr>
|
|
|
|
# Stack objects
|
|
# Count >= 7
|
|
# Subtract 6 count objects
|
|
# Leaves us at least 1 (nullptr)
|
|
sub x1, x1, 6
|
|
|
|
# Round up to the nearest pair
|
|
and x10, x1, 1
|
|
add x10, x10, x1
|
|
|
|
# Multiply by eight to get the size of stack we need to create
|
|
lsl x10, x10, 3
|
|
|
|
# Allocate stack space
|
|
sub sp, sp, x10
|
|
|
|
# Store how much data we added to the stack in our callee saved register we stole
|
|
mov x28, x10
|
|
|
|
# Subtract one member due to nullptr ender
|
|
sub x10, x1, 1
|
|
|
|
# x11 - stack offset
|
|
mov x11, sp
|
|
|
|
# x12 - load offset
|
|
add x12, x9, (7 * 8)
|
|
|
|
cmp x10, 1
|
|
b.eq .single%=
|
|
b.lt .no_single%=
|
|
|
|
.load_pair%=:
|
|
ldp x1, x2, [x12], 16
|
|
stp x1, x2, [x11], 16
|
|
sub x10, x10, 8
|
|
cmp x10, 1
|
|
b.gt .load_pair%=
|
|
b.lt .no_single%=
|
|
|
|
# One variable at most
|
|
.single%=:
|
|
ldr x1, [x12]
|
|
stp x1, xzr, [x11]
|
|
b .top_reg_args%=
|
|
|
|
.no_single%=:
|
|
# Need to store nullptr
|
|
str xzr, [x11]
|
|
|
|
.top_reg_args%=:
|
|
ldp x1, x2, [x9, 0]
|
|
ldp x3, x4, [x9, 16]
|
|
ldp x5, x6, [x9, 32]
|
|
ldr x7, [x9, 48]
|
|
|
|
# Stack is setup going in to this
|
|
blr x8
|
|
|
|
# Move stack back
|
|
add sp, sp, x28
|
|
ldp x28, x30, [sp], 16
|
|
ret
|
|
|
|
.jump_table%=:
|
|
.byte (.zero%= - .zero%=) >> 2
|
|
.byte (.one%= - .zero%=) >> 2
|
|
.byte (.two%= - .zero%=) >> 2
|
|
.byte (.three%= - .zero%=) >> 2
|
|
.byte (.four%= - .zero%=) >> 2
|
|
.byte (.five%= - .zero%=) >> 2
|
|
.byte (.six%= - .zero%=) >> 2
|
|
)"
|
|
::: "memory"
|
|
);
|
|
}
|
|
|
|
#endif
|
|
|
|
_XIC *fexfn_impl_libX11_XCreateIC_internal(XIM a_0, size_t count, unsigned long *list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XCreateIC(a_0, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<_XIC*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XCreateIC)));
|
|
#else
|
|
fprintf(stderr, "XCreateIC_internal FAILURE\n");
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
char* fexfn_impl_libX11_XGetICValues_internal(XIC a_0, size_t count, unsigned long *list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XGetICValues(a_0, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XGetICValues)));
|
|
#else
|
|
fprintf(stderr, "XGetICValues_internal FAILURE\n");
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
char* fexfn_impl_libX11_XSetICValues_internal(XIC a_0, size_t count, unsigned long *list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XSetICValues(a_0, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XSetICValues)));
|
|
#else
|
|
fprintf(stderr, "XSetICValues_internal FAILURE\n");
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
char* fexfn_impl_libX11_XGetIMValues_internal(XIM a_0, size_t count, void **list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XGetIMValues(a_0, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XGetIMValues)));
|
|
#else
|
|
fprintf(stderr, "XGetIMValues_internal FAILURE\n");
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
char* fexfn_impl_libX11_XSetIMValues_internal(XIM a_0, size_t count, void **list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XSetIMValues(a_0, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XSetIMValues)));
|
|
#else
|
|
fprintf(stderr, "XSetIMValues_internal FAILURE\n");
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
XVaNestedList fexfn_impl_libX11_XVaCreateNestedList_internal(int unused_arg, size_t count, void** list) {
|
|
switch(count) {
|
|
case 0: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, nullptr); break;
|
|
case 1: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], nullptr); break;
|
|
case 2: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], nullptr); break;
|
|
case 3: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], nullptr); break;
|
|
case 4: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], nullptr); break;
|
|
case 5: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], list[4], nullptr); break;
|
|
case 6: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], list[4], list[5], nullptr); break;
|
|
case 7: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], list[4], list[5], list[6], nullptr); break;
|
|
case 8: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
|
default:
|
|
#ifdef _M_ARM_64
|
|
return reinterpret_cast<XVaNestedList>(libX11_Variadic_u64(unused_arg, count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XVaCreateNestedList)));
|
|
#else
|
|
fprintf(stderr, "XVaCreateNestedList_internal FAILURE\n");
|
|
abort();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
Status fexfn_impl_libX11_XInitThreadsInternal(uintptr_t, uintptr_t);
|
|
|
|
Status fexfn_impl_libX11__XReply(Display*, xReply*, int, Bool);
|
|
|
|
static int (*ACTUAL_XInitDisplayLock_fn)(Display*) = nullptr;
|
|
static int (*INTERNAL_XInitDisplayLock_fn)(Display*) = nullptr;
|
|
|
|
static int _XInitDisplayLock(Display* display) {
|
|
auto ret = ACTUAL_XInitDisplayLock_fn(display);
|
|
INTERNAL_XInitDisplayLock_fn(display);
|
|
return ret;
|
|
}
|
|
|
|
Status fexfn_impl_libX11_XInitThreadsInternal(uintptr_t GuestTarget, uintptr_t GuestUnpacker) {
|
|
auto ret = fexldr_ptr_libX11_XInitThreads();
|
|
auto _XInitDisplayLock_fn = (int(**)(Display*))dlsym(fexldr_ptr_libX11_so, "_XInitDisplayLock_fn");
|
|
ACTUAL_XInitDisplayLock_fn = std::exchange(*_XInitDisplayLock_fn, _XInitDisplayLock);
|
|
MakeHostTrampolineForGuestFunctionAt(GuestTarget, GuestUnpacker, &INTERNAL_XInitDisplayLock_fn);
|
|
return ret;
|
|
}
|
|
|
|
Status fexfn_impl_libX11__XReply(Display* display, xReply* reply, int extra, Bool discard) {
|
|
for(auto handler = display->async_handlers; handler; handler = handler->next) {
|
|
FinalizeHostTrampolineForGuestFunction(handler->handler);
|
|
}
|
|
return fexldr_ptr_libX11__XReply(display, reply, extra, discard);
|
|
}
|
|
|
|
EXPORTS(libX11)
|