C 将对象文件转换为二进制代码

C 将对象文件转换为二进制代码,c,gcc,ld,C,Gcc,Ld,假设我有一个没有外部依赖关系的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

假设我有一个没有外部依赖关系的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--;
    }
}
我想把它编译成f1.o,然后是f1.bin,然后像这样使用它 在程序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);
}
我想从f1.c到f1.o涉及到-fPIC以获得位置独立性。我可以使用哪些标志或链接器脚本 从f1.o转到f1.bin

澄清:

我知道动态链接。在这种情况下,不可能进行动态链接。如果可能的话,链接步骤必须转换为加载数据的func指针

请假定没有操作系统支持。如果可以的话,比如说,我会的
使用PC相关地址在程序集中写入f1

> P>您应该考虑构建一个共享的库(< Windows >强> > DLL<强> >或<强> .SO > Linux。

按如下方式构建库:

gcc -c -fPIC test.c
gcc -shared test.o -o libtest.so
如果要从代码中动态加载库,请查看函数dlopen(3)dlsym(3)

如果要在编译时链接库,请使用

gcc -c main.c
gcc main.o -o <binary name> -ltest
gcc-cmain.c
gcc main.o-o-ltest
编辑:

我真的不确定我将在这里说什么,但这可以给你一个线索,让你在你的研究进展

如果不想使用dlopendlsym,可以尝试从.o文件中读取符号表以查找函数地址,然后,mmap在内存中读取具有读取和执行权限的对象文件。然后,您应该能够在找到的地址执行加载的代码。但要小心处理在这段代码中可能遇到的其他依赖项


你可以检查man页面<代码>精灵(5)< /> > /p> < p>首先,正如其他人所说的,你应该考虑使用DLL等。 也就是说,如果您真的想这样做,您需要替换链接器脚本。类似这样的东西(没有经过很好的测试,但我认为它是有效的):

然后使用以下命令进行编译:

$ gcc -c -fPIC test.c
链接:

$ ld -T script.ld test.o -o test.elf
并使用以下命令提取二进制blob:

$ objcopy -j .all -O binary test.elf test.bin
可能欢迎对脚本进行一些解释:

  • ENTRY(\u dummy\u start)
    它只是避免了程序没有入口点的警告
  • \u dummy\u start=0。未使用该值
  • \u全局\u偏移量\u表\u0。我不认为你真的需要这个符号,所以它可以定义为0
  • .all
    这是将收集blob的所有字节的部分的名称。在本示例中,所有
    .text
    .data
    .rodata
    部分将放在一起。如果您有复杂的函数,可能还需要一些,在本例中,
    objdump-x test.o
    是您的朋友
  • LONG(f1-\u all)
    实际上不需要,但是您想知道函数在blob中的偏移量,不是吗?不能假定它将位于偏移量0处。在这一行中,blob中的前4个字节将是符号
    f1
    (您的函数)的偏移量。如果使用64位指针,则使用
    QUAD
    更改
    LONG
更新:现在是一个快速的“不脏”测试(它可以工作!):

#包括
#包括
#包括
typedef void(*f1_t)(字符*a,字符*b,整数长度);
f1_t f1;
int main()
{
char*blob=(char*)valloc(4096);
文件*f=fopen(“test.bin”、“rb”);
fread(blob,14096,f);
fclose(f);
无符号关闭=*(无符号*)blob;
f1=(f1_t)(水滴+关闭);
mprotect(blob,4096,PROT_READ | PROT_WRITE | PROT_EXEC);
char txt[]=“你好,世界!”;
char txt2[sizeof(txt)]=“”;
f1(txt,txt2,sizeof(txt)-1);
printf(“%s\n%s\n”,txt,txt2);
返回0;
}

使用强制转换函数指针

下面是一个例子:

#include <stdio.h>

int main()
{
    unsigned char *dst, *src;
    int len;
    void (*f1)(unsigned char *, unsigned char *, int);
    *(void **)(&f1) = 0x..........;
    f1(src,dst,len);
    return 0;
}
#包括
int main()
{
无符号字符*dst,*src;
内伦;
void(*f1)(无符号字符*,无符号字符*,int);
*(void**)(&f1)=0x。。。。。。。。。。;
f1(src、dst、len);
返回0;
}

若要执行更多操作,您确实需要一个链接器和一个动态加载程序。

您知道可以使用共享对象文件吗?将.c文件编译为.so,然后将其加载到程序中,并获取指向该函数的函数指针
dlsym()
。然后你可以调用它。让我们忘记libc和动态链接你想要动态加载
f1.bin
thingie(即在运行时)?然后您必须构建一个共享库,并使用ldopen()+ldsym()或其他模块加载程序(如gmodule)。尝试其他方式很可能会很困难,并且会因为潜在的安全威胁(执行数据段等)而被拒绝。我确实不想使用动态链接,根据DLOPEN和dlsym编辑问题并不意味着动态链接(由于您的程序不会链接到库,因此二进制文件不会依赖于它,并且在编译过程中不需要库)。函数dlopen允许您加载库,dlsym将根据您提供的符号名称返回函数地址。dlsym意味着调用操作系统提供的动态链接器来分析库文件、执行映射等…
\u GLOBAL\u OFFSET\u TABLE\如果引用其他符号(如标准库),则可能需要@APProgrammer:但OP明确表示没有外部依赖,因此可能不需要。如果他访问任何库,那么他必须静态链接blob中的所有库,或者自己进行动态链接……这将……非常复杂。
#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;

}
#include <stdio.h>

int main()
{
    unsigned char *dst, *src;
    int len;
    void (*f1)(unsigned char *, unsigned char *, int);
    *(void **)(&f1) = 0x..........;
    f1(src,dst,len);
    return 0;
}