First of all, like others, you should consider using a DLL or SO.
However, if you really want to do this, you need to replace the script linker. Something like this (not very well tested, but I think it works):
ENTRY(_dummy_start) SECTIONS { _dummy_start = 0; _GLOBAL_OFFSET_TABLE_ = 0; .all : { _all = .; LONG(f1 - _all); *( .text .text.* .data .data.* .rodata .rodata.* ) } }
Then compile with:
$ gcc -c -fPIC test.c
Link to:
$ ld -T script.ld test.o -o test.elf
And extract the binary block with:
$ objcopy -j .all -O binary test.elf test.bin
Perhaps some explanation of the script is welcome:
ENTRY(_dummy_start) This simply prevents a warning that the program does not have an entry point._dummy_start = 0; Defines the character used in the previous line. The value is not used._GLOBAL_OFFSET_TABLE_ = 0; This prevents a different linker error. I donβt think you really need this symbol, so it can be defined as 0..all This is the name of the section that will collect all the bytes of your blob. This sample will contain all .text , .data and .rodata . You may need some more if you have complex functions, in which case objdump -x test.o is your friend.LONG(f1 - _all) Not necessary, but you want to know the offset of your function in the blob, right? You cannot assume that it will be at offset 0. With this string, the first 4 bytes in the block will be the offset of the character f1 (your function). Change LONG to QUAD if using 64-bit pointers.
UPDATE . And now the quick'n'dirty test (it works!):
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> typedef void (*f1_t)(char *a, char *b, int len); f1_t f1; int main() { char *blob = (char*)valloc(4096); FILE *f = fopen("test.bin", "rb"); fread(blob, 1, 4096, f); fclose(f); unsigned offs = *(unsigned*)blob; f1 = (f1_t)(blob + offs); mprotect(blob, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); char txt[] = "Β‘hello world!"; char txt2[sizeof(txt)] = ""; f1(txt, txt2, sizeof(txt) - 1); printf("%s\n%s\n", txt, txt2); return 0; }
source share