假设我有一个没有外部依赖关系的C文件,只有const数据部分.我想编译这个文件,然后得到一个二进制blob,我可以在另一个程序中加载,该函数将通过函数指针使用.
我们举一个例子,这是一个虚构的二进制模块,f1.c
static const unsigned char mylut[256] = {
[0 ... 127] = 0,
[128 ... 255] = 1,
};
void f1(unsigned char * src, unsigned char * dst, int len)
{
while(len) {
*dst++ = mylut[*src++];
len--;
}
}
Run Code Online (Sandbox Code Playgroud)
我想将它编译为f1.o,然后f1.bin,并在prog.c中使用它
int somefunc() {
unsigned char * codedata;
f1_type_ptr f1_ptr;
/* open f1.bin, and read it into codedata */
/* set function pointer to beginning of loaded data */
f1_ptr =(f1_type_ptr)codedata;
/* call !*/
f1_ptr(src, dst, len);
}
Run Code Online (Sandbox Code Playgroud)
我想从f1.c到f1.o涉及-fPIC以获得位置独立性.我可以使用从f1.o到f1.bin的标志或链接描述符是什么?
澄清:
我知道动态链接.在这种情况下,动态链接是不可能的.如果可能的话,链接步骤必须是指向加载数据的func指针.
请假设没有OS支持.如果可以的话,我会例如在装配PC的相关地址中写f1.
rod*_*igo 12
首先,正如其他人所说,你应该考虑使用DLL或SO.
也就是说,如果你真的想这样做,你需要替换链接器脚本.像这样的东西(测试不是很好,但我觉得它有效):
ENTRY(_dummy_start)
SECTIONS
{
_dummy_start = 0;
_GLOBAL_OFFSET_TABLE_ = 0;
.all : {
_all = .;
LONG(f1 - _all);
*( .text .text.* .data .data.* .rodata .rodata.* )
}
}
Run Code Online (Sandbox Code Playgroud)
然后编译:
$ gcc -c -fPIC test.c
Run Code Online (Sandbox Code Playgroud)
链接:
$ ld -T script.ld test.o -o test.elf
Run Code Online (Sandbox Code Playgroud)
并提取二进制blob:
$ objcopy -j .all -O binary test.elf test.bin
Run Code Online (Sandbox Code Playgroud)
可能会对脚本进行一些解释:
ENTRY(_dummy_start) 这只是避免了关于没有入口点的程序的警告._dummy_start = 0;这定义了前一行中使用的符号.该值未使用._GLOBAL_OFFSET_TABLE_ = 0;这可以防止其他链接器错误 我认为你真的不需要这个符号,所以它可以定义为0..all这是收集blob所有字节的部分的名称.在此示例中这将是所有的.text,.data和.rodata部分在一起.如果你有复杂的功能,你可能需要更多,在这种情况下objdump -x test.o你的朋友.LONG(f1 - _all)不是真的需要,但是你想知道你的函数偏移到blob中,不是吗?您不能假设它将在偏移0处.使用此行,blob中的前4个字节将是符号f1(您的函数)的偏移量.更改LONG与QUAD如果使用64位指针.更新:现在一个快速的测试(它的工作!):
#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;
}
Run Code Online (Sandbox Code Playgroud)
您应该考虑构建一个共享库(对于 Windows 为.dll,对于Linux为.so )。
像这样构建库:
gcc -c -fPIC test.c
gcc -shared test.o -o libtest.so
Run Code Online (Sandbox Code Playgroud)
如果您想从代码中动态加载库,请查看函数dlopen(3)和dlsym(3)。
或者,如果您想在编译时链接库,请使用以下命令构建程序
gcc -c main.c
gcc main.o -o <binary name> -ltest
Run Code Online (Sandbox Code Playgroud)
编辑:
我真的不确定我会在这里说什么,但这可以为您的研究进展提供线索......
如果不想使用dlopen和dlsym,可以尝试从.o文件中读取符号表来找到函数地址,然后将目标文件映射到内存中,并具有读取和执行权限。然后您应该能够在您找到的地址执行加载的代码。但请小心此代码中可能遇到的其他依赖项。
您可以查看手册页elf(5)
| 归档时间: |
|
| 查看次数: |
3732 次 |
| 最近记录: |