Created
May 10, 2022 19:57
-
-
Save withs/d1acf170065719924feb37005a21f83b to your computer and use it in GitHub Desktop.
Create Cxx classes with methods and members In V (poc)
This file contains 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
// I have a special case where i need to create and give a c++ class with virtual methods, | |
// so i came up with this proof of concept. | |
// Known limitation: | |
// - accesing class member/methods from "this" is pertty impossible without storing the Cxx struct globaly | |
// - you can't pass struct methods since the struct ptr will overwrite the real "this" ptr | |
// use it: | |
// v -enable-globals -shared vxx.v (work well with autofree and prod) | |
// g++ vxx_class.cc | |
// utils fns (those aren't used in the project but they are pretty usefull when working with c++ classes free cool cool code :]) | |
[inline] | |
pub fn get_virtual(in_this_class voidptr, at_index int) voidptr { | |
return unsafe { ((*(&&voidptr(in_this_class)))[at_index]) } | |
} | |
// v_fn_add := get_virtual(class_ptr, v_fn_idx)(class_ptr, args) | |
[inline] | |
fn call_vfunc<T>(from_class voidptr, at_idx int) T { | |
return T(get_virtual(from_class, at_idx)) | |
} | |
// v_fn_ret_if_needed := call_vfunc<fn_proto>(class_ptr, v_fn_idx)(class_ptr, args) | |
// CXX Class implementation | |
struct CXXClass<T, Y> { | |
pub mut: | |
buff []u8 = []u8{len: int(sizeof(usize) + sizeof(Y))} | |
members &T = 0 | |
methods Y | |
raw_class_ptr voidptr | |
} | |
pub fn new_cxx_class<T, Y>() &CXXClass<T, Y> { | |
mut cc := &CXXClass<T, Y>{} | |
unsafe { | |
*(&usize(cc.buff.data)) = &cc.methods | |
} | |
cc.members = &T(usize(cc.buff.data) + sizeof(usize)) | |
cc.raw_class_ptr = cc.buff.data | |
return cc | |
} | |
// tests | |
[callconv: 'fastcall'] | |
type P_hello = fn (ecx voidptr, edx usize) | |
[callconv: 'fastcall'] | |
type P_cool = fn (ecx voidptr, edx usize, real_arg int) bool | |
[callconv: 'fastcall'] | |
fn hello(ecx voidptr, edx usize) { | |
dump('hello') | |
} | |
[callconv: 'fastcall'] | |
fn cool(ecx voidptr, edx usize, real_arg int) bool { | |
dump('cool -> $real_arg') | |
return true | |
} | |
[callconv: 'fastcall'] | |
fn destructor() { | |
dump('deconstructed') | |
} | |
struct MyClassMethods { | |
hello P_hello = hello | |
cool P_cool = cool | |
pad voidptr = voidptr(0) // needed if destructor is present, and it must be before the destructor | |
destructor voidptr = destructor | |
} | |
struct MyClassMembers { | |
pub mut: | |
a int | |
ab [3]u8 | |
abc &usize = 0 | |
} | |
__global ( | |
cc = new_cxx_class<MyClassMembers, MyClassMethods>() | |
) | |
[export: 'make_vxx'] | |
pub fn make_vxx() voidptr { | |
cc = new_cxx_class<MyClassMembers, MyClassMethods>() | |
return cc.raw_class_ptr | |
} | |
[export: 'action'] | |
pub fn action() { | |
cc.members.a = 123_670_667 | |
cc.members.ab = [u8(123), 67, 66]! | |
cc.members.abc = voidptr(hello) | |
cc.methods.hello(cc.raw_class_ptr, 0) | |
} |
This file contains 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
#include "iostream" | |
#include <dlfcn.h> | |
class VxxClass { | |
public: | |
int a; | |
char ab[3]; | |
void* abc; | |
virtual void hello() = 0; | |
virtual bool cool(int arg) = 0; | |
virtual ~VxxClass() = 0; | |
}; | |
typedef void* (*Make_vxx)(); | |
typedef void (*Action)(); | |
int main(int argc, char const *argv[]) { | |
void* a = dlopen("vxx.dylib", RTLD_LAZY); | |
Make_vxx make_vxx = (Make_vxx) dlsym(a, "make_vxx"); | |
Action action = (Action) dlsym(a, "action"); | |
VxxClass* here = (VxxClass*)(make_vxx()); | |
std::cout << here << std::endl; | |
here->hello(); | |
std::cout << here->cool(123) << '\n'; | |
std::cout << "here->a " << here->a << '\n'; | |
std::cout << "here->ab " << here->ab[0] << " - "<< here->ab[1] << " - " << here->ab[2] << '\n'; | |
std::cout << "here->abc " << here->abc << '\n'; | |
action(); | |
std::cout << "here->a " << here->a << '\n'; | |
std::cout << "here->ab " << here->ab[0] << " - "<< here->ab[1] << " - " << here->ab[2] << '\n'; | |
std::cout << "here->abc " << here->abc << '\n'; | |
delete here; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
result: