Last active
June 10, 2022 09:48
-
-
Save skmp/eefb284b5e353ef4dcc5bb5784c55665 to your computer and use it in GitHub Desktop.
copyable functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //More details: https://github.com/FEX-Emu/fex-assorted-tests-bins/tree/main/src/copyable-functions | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #include <sys/mman.h> | |
| // Example of creating function specializations at run time from a "canonical" template provided by the compiler | |
| #include "copyable-functions.h" | |
| DECL_COPYABLE_TRAMPLOLINE(one_name, int, int, const char *) | |
| DECL_COPYABLE_TRAMPLOLINE(two_name, int, const char *, int) | |
| /* | |
| // Oof, this cannot be done | |
| template __attribute__((section("test_func_section"))) auto CopyableTrampoline<decltype(test_func)>:: | |
| trampoline_canonical(Args...) -> rv_t; | |
| */ | |
| int test_func (int a, const char *b); | |
| int test_func_marshaler (int a, const char *b, decltype(&test_func) fn_ptr) { | |
| printf("%s: Called with %d, %s, %p\n", __func__, a, b, fn_ptr); | |
| return fn_ptr(a, b); | |
| } | |
| int test_func_to_call_1(int a, const char *b) { printf("%s: Called with %d, %s\n", __func__, a, b); return -1; } | |
| int test_func_to_call_2(int a, const char *b) { printf("%s: Called with %d, %s\n", __func__, a, b); return -2; } | |
| int test_func2 (const char *a, int b); | |
| int test_func2_marshaler (const char *a, int b, decltype(&test_func2) target) { | |
| printf("%s: Called with %s, %d, %p\n", __func__, a, b, target); | |
| return target(a, b); | |
| } | |
| int test_func2_to_call_1(const char *b, int a) { printf("%s: Called with %d, %s\n", __func__, a, b); return -1; } | |
| int test_func2_to_call_2(const char *b, int a) { printf("%s: Called with %d, %s\n", __func__, a, b); return -2; } | |
| int main (void) | |
| { | |
| auto fn1 = make_one_name_instance(&test_func_to_call_1, &test_func_marshaler); | |
| auto fn2 = make_one_name_instance(&test_func_to_call_2, &test_func_marshaler); | |
| auto fn3 = make_two_name_instance(&test_func2_to_call_2, &test_func2_marshaler); | |
| auto fn4 = make_two_name_instance(&test_func2_to_call_2, &test_func2_marshaler); | |
| auto rv1 = fn1(1, "test stuff here 1"); | |
| printf("rv1: %d\n", rv1); | |
| auto rv2 = fn2(2, "test stuff here 2"); | |
| printf("rv2: %d\n", rv2); | |
| auto rv3 = fn3("test stuff here 1", 3); | |
| printf("rv3: %d\n", rv1); | |
| auto rv4 = fn4("test stuff here 2", 4); | |
| printf("rv4: %d\n", rv2); | |
| return 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //More details: https://github.com/FEX-Emu/fex-assorted-tests-bins/tree/main/src/copyable-functions | |
| template<typename Fn> | |
| struct CopyableTrampoline; | |
| template<typename R, typename... Args> | |
| struct CopyableTrampoline<R(Args...)> { | |
| using rv_t = R; | |
| using target_t = R(Args...); | |
| using marshaler_t = R(Args..., target_t *target); | |
| struct instance_info_t { | |
| target_t *target; | |
| marshaler_t *marshaler; | |
| }; | |
| static R trampoline_canonical(Args... args) { | |
| //instance_info *info; | |
| //asm("movabs $0xAABBCCDDEEFF0011, %0" : "=r" (info)); | |
| auto info = (instance_info_t*)&instance_info_canonical; | |
| return info->marshaler(args..., info->target); | |
| } | |
| static __attribute__((aligned(16), naked)) void instance_info_canonical() { | |
| __asm__(".quad 0"); | |
| __asm__(".quad 0"); | |
| } | |
| static target_t *make_instance(target_t *target, marshaler_t *marshaler, char *section_start, char *section_end) { | |
| auto section_size = section_end - section_start; | |
| printf ("Section len: %d\n", (int)section_size); | |
| // alloc | |
| auto instance = (uint8_t*)mmap(0, section_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
| // copy | |
| memcpy(instance, section_start, section_size); | |
| // bind | |
| auto code_offset = (uintptr_t)&trampoline_canonical - (uintptr_t)section_start; | |
| auto info_offset = (uintptr_t)&instance_info_canonical - (uintptr_t)section_start; | |
| printf("code_offset offset: %d\n", (int)code_offset); | |
| printf("info_offset offset: %d\n", (int)info_offset); | |
| auto info = (instance_info_t*)(instance + info_offset); | |
| #if defined(ADDR_PATCH) | |
| auto patch_offset = (uintptr_t)&test_func_canonical_patch - (uintptr_t)__start_test_func_section; | |
| printf("patch_offset offset: %d\n", (int)patch_offset); | |
| auto patch = (instance_info_t**)(instance + patch_offset + 2); // +2 is architecture specific | |
| printf("Patching: %p from %p to %p\n", patch, *patch, info); | |
| *patch = info; | |
| #endif | |
| info->target = target; | |
| info->marshaler = marshaler; | |
| return (target_t *)(instance + code_offset); | |
| } | |
| }; | |
| #define DECL_COPYABLE_TRAMPLOLINE(name, rv, ...) \ | |
| template __attribute__((section(#name "_copy_section"))) void CopyableTrampoline<rv(__VA_ARGS__)>::instance_info_canonical(); \ | |
| template __attribute__((section(#name "_copy_section"))) auto CopyableTrampoline<rv(__VA_ARGS__)>:: \ | |
| trampoline_canonical(__VA_ARGS__) -> rv_t; \ | |
| template auto CopyableTrampoline<rv(__VA_ARGS__)>:: \ | |
| make_instance(target_t *target, marshaler_t *marshaler, char *section_start, char *section_end) -> target_t *; \ | |
| CopyableTrampoline<rv(__VA_ARGS__)>::target_t *make_##name##_instance(CopyableTrampoline<rv(__VA_ARGS__)>::target_t *target, CopyableTrampoline<rv(__VA_ARGS__)>::marshaler_t *marshal) { \ | |
| extern char __start_##name##_copy_section[]; \ | |
| extern char __stop_##name##_copy_section[]; \ | |
| return CopyableTrampoline<rv(__VA_ARGS__)>::make_instance(target, marshal, __start_##name##_copy_section, __stop_##name##_copy_section); \ | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment