If I write a simple library, e.g.
void swap(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
After compiled to a static library, say "swap.a", is it possible to call this function and link from a kernel code?
This question says linking shared library in kernel is impossible, because loading a shared library demands a loader, which is running on user space. But I don't understand why static library cannot be used in kernel space, as the loader is not needed.
Related
I am reading the source code implementation of libext2fs, which is part of the project e2fsprogs used to debug Ext2/3/4 file systems. And came across one confused point about the use of method memcpy as follows.
In the library, it maintains one function ext2fs_get_mem which is used to allocate dynamic memories:
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return EXT2_ET_NO_MEMORY;
memcpy(ptr, &pp, sizeof (pp));
return 0;
}
The caller will call it like:
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs)
In the above case, variable fs is just type of struct struct_ext2_filsys, all right.
The confused point is why the function ext2fs_get_mem need to call memcpy and what's the purpose? Why not directly allocate memory to the pointer void *ptr by malloc?
I have an aarch64 library for Linux and I want to use it from within an amd64 Linux install. Currently, I know one method of getting this to work, which is to use the qemu-arm-static binary emulator with an aarch64 executable I compile myself, that calls dlopen on the aarch64 library and uses it.
The annoyance is that integrating the aarch64 executable with my amd64 environment is annoying (eg. let's say, for example, this arm64 library is from an IoT device and decodes a special video file in real time—how am I supposed to use the native libraries on my computer to play it?). I end up using UNIX pipes, but I really dislike this solution.
Is there a way I can use the qemu-arm-static stuff only with the library, so I can have an amd64 executable that directly calls the library? If not, what's the best way to interface between the two architectures? Is it pipes?
The solution that I implemented for this is to use shared memory IPC. This solution is particularly nice since it integrates pretty well with fixed-length C structs, allowing you to simply just use a struct on one end and the other end.
Let's say you have a function with a signature uint32_t so_lib_function_a(uint32_t c[2])
You can write a wrapper function in an amd64 library: uint32_t wrapped_so_lib_function_a(uint32_t c[2]).
Then, you create a shared memory structure:
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
Initialise a struct like this, and then run shmget(SOME_SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);, get the return value from that, and then get a pointer to the shared memory. Then copy the initialised struct into shared memory.
You then run shmget(3) and shmat(3) on the ARM binary side, getting a pointer to the shared memory as well. The ARM binary runs an infinite loop, waiting for its "turn." When turn is set to 1, the amd64 binary will block in a forever loop until the turn is 0. The ARM binary will execute the function, using the shared struct details as parameters and updating the shared memory struct with the return value. Then the ARM library will set the turn to 0 and block until turn is 1 again, which will allow the amd64 binary to do its thing until it's ready to call the ARM function again.
Here is an example (it might not compile yet, but it gives you a general idea):
Our "unknown" library : shared.h
#include <stdint.h>
#define MAGIC_NUMBER 0x44E
uint32_t so_lib_function_a(uint32_t c[2]) {
// Add args and multiplies by MAGIC_NUMBER
uint32_t ret;
for (int i = 0; i < 2; i++) {
ret += c[i];
}
ret *= MAGIC_NUMBER;
return ret;
}
Hooking into the "unknown" library: shared_executor.c
#include <dlfcn.h>
#include <sys/shm.h>
#include <stdint.h>
#define SHM_KEY 22828 // Some random SHM ID
uint32_t (*so_lib_function_a)(uint32_t c[2]);
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
int main() {
ipc_call_struct *handle;
void *lib_dlopen = dlopen("./shared.so", RTLD_LAZY);
so_lib_function_a = dlsym(lib_dlopen, "so_lib_function_a");
// setup shm
int shm_id = shmget(SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);
handle = shmat(shm_id, NULL, 0);
// We expect the handle to already be initialised by the time we get here, so we don't have to do anything
while (true) {
if (handle->turn == 1) { // our turn
handle->ret = so_lib_function_a(handle->c);
handle->turn = 0; // hand off for later
}
}
}
On the amd64 side: shm_shared.h
#include <stdint.h>
#include <sys/shm.h>
typedef struct {
uint32_t c[2];
uint32_t ret;
int turn; // turn = 0 means amd64 library, turn = 1 means arm library
} ipc_call_struct;
#define SHM_KEY 22828 // Some random SHM ID
static ipc_call_struct* handle;
void wrapper_init() {
// setup shm here
int shm_id = shmget(SHM_KEY, sizeof(ipc_call_struct), IPC_CREAT | 0777);
handle = shmat(shm_id, NULL, 0);
// Initialise the handle
// Currently, we don't want to call the ARM library, so the turn is still zero
ipc_call_struct temp_handle = { .c={0}, .ret=0, .turn=0 };
*handle = temp_handle;
// you should be able to fork the ARM binary using "qemu-arm-static" here
// (and add code for that if you'd like)
}
uint32_t wrapped_so_lib_function_a(uint32_t c[2]) {
handle->c = c;
handle->turn = 1; // hand off execution to the ARM librar
while (handle->turn != 0) {} // wait
return handle->ret;
}
Again, there's no guarantee this code even compiles (yet), but just a general idea.
I can use the function of the kernel code on a module or other code using EXPORT_SYMBOL.
Conversely, I would like to use the function of the kernel module using EXPORT_SYMBOL in the kernel code.
Do I have any option for this?
When load the kernel core, the loader should resolve every symbol(function) which is used by kernel core.
Because kernel modules are not available when the kernel core is loaded, the kernel core cannot directly use symbols, defined in the modules.
However, the kernel core can have a pointer, which can be initialized by the module's code when it is loaded. This can be treated as some sort of registration procedure:
foo.h:
// Header used by both kernel core and modules
// Register 'foo' function.
void register_foo(int (*foo)(void));
foo.c:
// compiled as a part of the kernel core
#include <foo.h>
// pointer to the registered function
static int (*foo_pointer)(void) = NULL;
// Implement the function provided by the header.
void register_foo(int (*foo)(void))
{
foo_pointer = foo;
}
// make registration function available for the module.
EXPORT_SYMBOL(register_foo);
// Calls foo function.
int call_foo(void)
{
if (foo_pointer)
return foo_pointer(); // call the registered function by pointer.
else
return 0; // in case no function is registered.
}
module.c:
// compiled as a module
#include <foo.h>
// Implement function
int foo(void)
{
return 1;
}
int __init module_init(void)
{
// register the function.
register_foo(&foo);
// ...
}
I'm using dlopen() and dlclose() to load and unload a module. The module contains some static data which needs to be destructed when dlclose() is called. However I'm finding that under certain circumstances dlclose() does not call the destructors - instead they are only called when main() exits.
I've boiled my code down to this. I have a class which contains a virtual function getType() defined inside the class, making reference to static data. I also have a StaticDestructionChecker object which just prints when the static constructors and destructors are being called. Finally I have a main() function that loads everything else via dlopen(), closes it via dlclose() and prints when main() is finished:
module1.h
#ifndef MODULE1_H
#define MODULE1_H
class MyClass
{
public:
MyClass();
virtual ~MyClass();
virtual int& getType() const
{
static int t(123);
return t;
}
};
#endif // MODULE1_H
module1.cpp
#include <stdio.h>
#include "module1.h"
MyClass::MyClass()
{
}
MyClass::~MyClass()
{
}
class StaticDestructionChecker
{
public:
StaticDestructionChecker()
{
printf("Constructing static data\n");
}
~StaticDestructionChecker()
{
printf("Destructing static data\n");
}
};
StaticDestructionChecker checker;
main:
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
void* handle = dlopen("module1.so", RTLD_NOW);
if (!handle) printf("dlopen error: %s\n", dlerror());
dlclose(handle);
printf("end of main\n");
return 0;
}
Running all this as-is causes the static data to be destructed after main terminates, ie the output is:
Constructing static data
end of main
Destructing static data
The problem is with the virtual/static combo in getType(). If I change getType() to be non-virtual OR if I remove the "static int t", the destructors get called when expected, ie output is:
Constructing static data
Destructing static data
end of main
Is there a way to get the correct destruction order while still keeping the virtual/static code? FYI this is a simplified version of a sort of custom RTTI system, where getType() is automatically generated via a DECLARE_xxx macro, so I don't want to move the implementation into the cpp file because there would need to be a second macro call in there too.
I am using GCC 4.8 on Ubuntu 12.
Thanks
See dlclose() doesn't work with factory function & complex static in function?
If you use gold linker than passing --no-gnu-unique flag when linking module1.so fixes the problem:
]$ g++ -o module1.so -shared -fPIC -Wl,--no-gnu-unique module1.cpp
]$ g++ main.cpp -ldl
]$ LD_LIBRARY_PATH=. ./a.out
Constructing static data
Destructing static data
end of main
I don't know what are other consequences of using that flag.
I am new to module writing and need a circular buffer[1] and a vector. Since the Linux kernel apparently provides some data structures (lib) (list, trees), I was wondering if there is a vector equivalent?
While I think I am well capable to write my own, I prefer libraries for such things to prevent the duplication of code and to avoid errors.
[1] Found while composing the question, kfifo, also Queues in the Linux Kernel might be of interest.
As far as I know there is no implementation of vectors till 4.1 Linux kernel. And it does not make any sense to have one as vectors can be designed with the basic data structures whose implementation is already provided in Linux kernel.
I'm a bit late, but if anyone needs to implement a generalized vector in C, it can be done using void pointers and a sizeof operator on initialization. It would look something like this:
struct MyVec {
void *data;
size_t stored_sizeof;
size_t size;
size_t allocated_size
};
#define STARTING_ALLOCATED_SIZE 10
void MyVec_init(struct MyVec *self, size_t sizeof_data_type) {
self->stored_sizeof = sizeof_data_type;
self->data = malloc(self->stored_sizeof * STARTING_ALLOCATED_SIZE);
self->size = 0;
self->allocated_size = STARTING_ALLOCATED_SIZE;
}
void MyVec_deinit(struct MyVec *self) {
free(self->data);
}
bool MyVec_at(struct MyVec *self, size_t index, void *to_fill) {
if (index >= size)
return false;
memcpy(to_fill, self->data + (index * self->stored_sizeof), self->stored_sizeof);
return true;
}
and all the other methods that you might need, just being sure to use stored_sizeof whenever indexing, adding/removing elements, and the like.