#include <unistd.h>
struct got_entry {
void *address;
char *symbol_name;
};
__attribute__((section(".data.got")))
struct got_entry got[] = {
{ 0, "write" },
{ 0, "printf" },
{ 0, "exit" },
{ 0, NULL }
};
typedef ssize_t (*write_func)(int, const void *, size_t);
typedef int (*printf_func)(const char *, ...);
typedef void (*exit_func)(int);
int main()
{
((write_func)got[0].address)(1, "Hello World!\n", 13);
((printf_func)got[1].address)("... and hello to dynamic linking!\n");
((exit_func)got[2].address)(0);
return 0;
}
/* Below is some magic code to actually fill in the GOT. You don't need
* to worry too much about it, only that it's run when the program is
* loaded. We'll imagine that the dynamic linker does this for us. */
#include <dlfcn.h>
#ifndef RTLD_DEFAULT
#define RTLD_DEFAULT 0
#endif
// Magic constructor function to fill in the GOT, using dlsym and GCC magic attributes
void __attribute__((constructor)) initialize_got()
{
for (int i = 0; got[i].symbol_name != NULL; i++) {
got[i].address = dlsym(RTLD_DEFAULT, got[i].symbol_name);
}
}