Skip to content

Commit 855c2e7

Browse files
committed
Implement library loader
1 parent 775ed55 commit 855c2e7

3 files changed

Lines changed: 148 additions & 42 deletions

File tree

src/executer/ExternalFunctions.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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

src/executer/ExternalFunctions.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
3+
#include "../error/Exceptions.h"
4+
5+
#include <string>
6+
#include <vector>
7+
#include <map>
8+
#include <iostream>
9+
10+
namespace ffi {
11+
12+
using word_t = unsigned long; // TODO?
13+
using dword_t = unsigned long;
14+
using qword_t = unsigned long long;
15+
16+
using float_t = float;
17+
using double_t = double;
18+
19+
enum class Type {
20+
Word,
21+
DWord,
22+
QWord,
23+
Float,
24+
Double
25+
};
26+
27+
struct ExternalFunction {
28+
std::string library;
29+
std::string name;
30+
void* functionPtr;
31+
std::vector<Type> parameters;
32+
Type returnType;
33+
};
34+
35+
class ExternalFunctions {
36+
public:
37+
ExternalFunctions();
38+
39+
size_t add(const std::string& library, const std::string& functionName);
40+
41+
qword_t call(size_t id, const std::vector<void*>& args);
42+
43+
~ExternalFunctions();
44+
45+
private:
46+
std::vector<ExternalFunction> functions;
47+
std::map<std::string, void*> libraries;
48+
};
49+
50+
} // namespace ffi

src/mains/Tests.cpp

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "../executer/ExternalFunctions.h"
12
#include "../executer/ByteCode.h"
23
#include <iostream>
34
#include "../core/Mlang.h"
@@ -120,50 +121,12 @@ void testFile(std::string path){
120121
std::cout << "[ OK ] " << path << std::endl;
121122
}
122123

123-
// TODO
124-
#include <dlfcn.h>
125-
126124
void testLibrary(){
127125
std::cout << "Testing library..." << std::endl;
128-
129-
void* handle = dlopen("bin/libprint.so", RTLD_LAZY);
130-
if (!handle) {
131-
std::cerr << "Error: " << dlerror() << std::endl;
132-
throwConstraintViolated("Failed to load library");
133-
}
134-
135-
dlerror(); // Clear any existing error
136-
137-
//void (*print)() = (void (*)())dlsym(handle, "print");
138-
void* fn = dlsym(handle, "mul");
139-
const char* dlsym_error = dlerror();
140-
if (dlsym_error) {
141-
std::cerr << "Error: " << dlsym_error << std::endl;
142-
dlclose(handle);
143-
throwConstraintViolated("Failed to find symbol in library");
144-
}
145-
146-
// print(); // Call the function from the library
147-
size_t result;
148-
__asm__ (
149-
"mov $5, %%rdi\n"
150-
"mov $10, %%rsi\n"
151-
"call *%[fn_tag]\n"
152-
"movq %%rax, %[result_tag]\n"
153-
: [result_tag] "=r"(result) : [fn_tag] "r"(fn)); // Call the function using inline assembly
154-
155-
// https://github.com/tsoding/b/blob/main/src/codegen/fasm_x86_64.rs#L221
156-
// Floating point numbers are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
157-
// Integer numbers are passed in rdi, rsi, rdx, rcx, r8, r9
158-
// The result is returned in rax
159-
// If we need more than 6 arguments, the rest are passed on the stack. (?)
160-
161-
162-
std::cout << "Result of multiplication: " << result << std::endl;
163-
164-
165-
dlclose(handle); // Close the library handle
166-
126+
ffi::ExternalFunctions externalFunctions;
127+
auto id = externalFunctions.add("print", "mul");
128+
auto r = externalFunctions.call(id, { }); // TODO: Args are not used yet
129+
EXPECT_EQ(50, r);
167130
std::cout << "[ OK ] Library test passed." << std::endl;
168131
}
169132

0 commit comments

Comments
 (0)