1+ #include " ../executer/ExternalFunctions.h"
2+ #include < dlfcn.h>
3+
4+ namespace ffi {
5+
6+ #ifdef WIN // Windows
7+
8+ ExternalFunctions::ExternalFunctions () = default;
9+
10+ size_t ExternalFunctions::add (const std::string& library, const std::string& functionName) {
11+ throwConstraintViolated (" External functions are not supported on this platform" );
12+ }
13+
14+ qword_t ExternalFunctions::call (size_t id, const std::vector<void *>& args) {
15+ throwConstraintViolated (" External functions are not supported on this platform" );
16+ return 0 ;
17+ }
18+
19+ ExternalFunctions::~ExternalFunctions () = default ;
20+
21+ #else // Linux
22+
23+ ExternalFunctions::ExternalFunctions () = default;
24+
25+ size_t ExternalFunctions::add (const std::string& library, const std::string& functionName) {
26+ ExternalFunction functionInfo;
27+ functionInfo.library = library;
28+ functionInfo.name = functionName;
29+ functionInfo.functionPtr = nullptr ;
30+
31+ void * libraryHandle = nullptr ;
32+ if (auto it = libraries.find (library); it != libraries.end ()) {
33+ libraryHandle = it->second ;
34+ } else {
35+ libraryHandle = dlopen ((" bin/lib" + library + " .so" ).c_str (), RTLD_LAZY);
36+ if (!libraryHandle) {
37+ std::cerr << " Error: " << dlerror () << std::endl;
38+ throwConstraintViolated (" Failed to load library" );
39+ }
40+ libraries[library] = libraryHandle;
41+ }
42+
43+ ASSURE_NOT_NULL (libraryHandle);
44+ dlerror (); // Clear any existing error
45+
46+ // void (*print)() = (void (*)())dlsym(handle, "print");
47+ functionInfo.functionPtr = dlsym (libraryHandle, functionName.c_str ());
48+ const char * dlsym_error = dlerror ();
49+ if (dlsym_error) {
50+ std::cerr << " Error: " << dlsym_error << std::endl;
51+ throwConstraintViolated (" Failed to find symbol in library" );
52+ }
53+ ASSURE_NOT_NULL (functionInfo.functionPtr );
54+
55+ functions.push_back (functionInfo);
56+ return functions.size () - 1 ;
57+ }
58+
59+ qword_t ExternalFunctions::call (size_t id, const std::vector<void *>& args) {
60+ ASSURE (id < functions.size (), " Function ID out of bounds" );
61+
62+ const ExternalFunction& func = functions[id];
63+
64+ qword_t result;
65+ void * fn = func.functionPtr ;
66+ __asm__ (
67+ " mov $5, %%rdi\n "
68+ " mov $10, %%rsi\n "
69+ " call *%[fn_tag]\n "
70+ " movq %%rax, %[result_tag]\n "
71+ : [result_tag] " =r" (result) : [fn_tag] " r" (fn)); // Call the function using inline assembly
72+
73+ // https://github.com/tsoding/b/blob/main/src/codegen/fasm_x86_64.rs#L221
74+ // Floating point numbers are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
75+ // Integer numbers are passed in rdi, rsi, rdx, rcx, r8, r9
76+ // The result is returned in rax
77+ // If we need more than 6 arguments, the rest are passed on the stack. (?)
78+
79+ return result;
80+ }
81+
82+ ExternalFunctions::~ExternalFunctions () {
83+ for (const auto & [libName, libHandle] : libraries) {
84+ if (libHandle) {
85+ dlclose (libHandle);
86+ }
87+ }
88+ libraries.clear ();
89+ }
90+
91+ #endif
92+
93+ } // namespace ffi
0 commit comments