Is there a way to reserve a particular range of virtual address space in a process memory map to stop ld.so (dynamic linker) from loading any shared objects into that range. Something like a system wide configuration option that reserves a particular range.
I want to be able to map a region of shared memory into exactly the same virtual address space in several processes so that my pointers in my data-structures will still work. I know I could redesign to use offsets instead of pointers but I don't want to do that.
You can do this by creating a simple shared object and running it via LD_PRELOAD. Compile the following code:
#include <sys/mman.h> // for mmap, munmap, and related constants
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void my_program_init() __attribute__((constructor));
void *const address = ((void*)0x10000000);
const int size = 0x1000;
void my_program_init() {
printf("Hello from my_program_init!\n");
int fd = shm_open("/mysharedmem", O_CREAT | O_RDWR, 0666);
if (fd == -1) {
printf("shm_open\n");
return;
}
if (ftruncate(fd, size) == -1) {
printf("ftruncate\n");
return;
}
void* shared_mem = mmap(address, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
if (shared_mem == MAP_FAILED) {
printf("mmap\n");
return;
}
return;
}
with the following options:
gcc -shared -fPIC -o libmylib.so myso.c
Then you can run your program like this:
LD_PRELOAD=./libmylib.so ./your_prog
The so is then loaded before any runtime linking happens in your program. The function in the so tagged as a constructor runs immediately and uses mmap to reserve the memory you want for your shared block.
You can see this working with the following example program:
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
int main() {
char *data = (char*)0x10000000;
const char *message = "Hello, world!\n";
memcpy(data, message, strlen(message));
printf("Wrote %ld bytes to memory at address %p %s\n", strlen(message), data, data);
return 0;
}
If you run this without the LD_PRELOAD it will segfault, but if you include the preload the shared block of memory is available as expected.
$ LD_PRELOAD=./libmylib.so ./a.out
Hello from my_program_init!
Wrote 14 bytes to memory at address 0x10000000 Hello, world!
You can construct your own tests to validate that the memory block is actually shared but the easiest check is to recompile the test program again without the memcpy and see that the string is still there from the first run of the program.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With