c-加载原始二进制文件

c-加载原始二进制文件,c,operating-system,elf,C,Operating System,Elf,是否可以执行存储在字符数组中的原始二进制文件?我试着这样做: #include "stdio.h" int main(int argc, char **argv) { FILE *f = fopen(argv[1],"r"); if(!f) return 1; fseek(f,0,SEEK_END); long l=ftell(f); rewind(f); char *buf = malloc(l+1); fread(buf

是否可以执行存储在字符数组中的原始二进制文件?我试着这样做:

#include "stdio.h"
int main(int argc, char **argv)
{
    FILE *f = fopen(argv[1],"r");
    if(!f)
        return 1;
    fseek(f,0,SEEK_END);
    long l=ftell(f);
    rewind(f);
    char *buf = malloc(l+1);
    fread(buf,1,l,f);
    fclose(f);
    void (*func)() = (void(*))buf;
    func();
}

但这只会给我带来缺点。我正在开发我自己的操作系统(从零开始),所以我正在摆脱它们。

很抱歉,这不是一个确切的答案,但它太长,无法作为一个评论

我将假设,将原始二进制文件读入缓冲区的目的是将代码字节读入RAM,并且您希望执行这些字节。假设您已经修复了文件I/O,那么现在您有了一个包含代码字节的缓冲区。有几个原因可以解释为什么你仍然会犯错

首先,您的O/S是否使用页面属性(如读、写和执行)实现虚拟内存?大多数现代O/S不允许在未标记为代码的页面上执行代码。(以这种方式标记页面对于了解可以交换的内容以及防止恶意编码非常重要。)

第二,您加载的二进制代码是完全可重定位的吗?换句话说,如果代码中有任何跳转,它们都是相对的吗?如果在它们的内存中有任何绝对跳转操作,那么您需要运行一个补丁,将它们排列到内存中的缓冲区位置

第三,二进制代码是100%自包含的吗?如果它调用任何外部函数,那么您也需要修补这些函数


最后,二进制代码是否需要访问数据?如果是这样的话,所有的数据都是二进制的,而且是相对地址还是绝对地址。

很抱歉,这不是一个确切的答案,但它太长,无法作为一个注释

我将假设,将原始二进制文件读入缓冲区的目的是将代码字节读入RAM,并且您希望执行这些字节。假设您已经修复了文件I/O,那么现在您有了一个包含代码字节的缓冲区。有几个原因可以解释为什么你仍然会犯错

首先,您的O/S是否使用页面属性(如读、写和执行)实现虚拟内存?大多数现代O/S不允许在未标记为代码的页面上执行代码。(以这种方式标记页面对于了解可以交换的内容以及防止恶意编码非常重要。)

第二,您加载的二进制代码是完全可重定位的吗?换句话说,如果代码中有任何跳转,它们都是相对的吗?如果在它们的内存中有任何绝对跳转操作,那么您需要运行一个补丁,将它们排列到内存中的缓冲区位置

第三,二进制代码是100%自包含的吗?如果它调用任何外部函数,那么您也需要修补这些函数


最后,二进制代码是否需要访问数据?如果是这样的话,所有数据是否也是二进制的,是否也是相对地址与绝对地址。

您可以这样做,但是:

  • 您不能(通常)像在这里使用
    malloc
    那样将可执行文件存储在堆中(出于同样的原因,也不能存储在堆栈中),因为如果您的硬件支持它,您的操作系统可能会将这些区域标记为可读、可写但没有可执行文件(或者至少应该这样做)

  • 您不能只获取已编译程序的代码,将其提取到文件中,然后期望运行它,因为它通常需要重新定位、导入动态库、为变量设置另一个虚拟内存区域

  • 您可以通过一个简单的手工程序来实现这一点,该程序可以对
    exit(0)
    ot打印“Hello World”

    您可能能够使用编译后的代码。为此,您需要(至少):

    • 编译一个自包含程序(没有导入的动态库,静态链接库并重新编译静态链接库)

    • 带有位置独立代码(
      -fpic
      -fpie

    • 没有任何重新定位(可能有帮助吗?
      -fvisibility=hidden)

    如果您能够做到这一点,您可能能够从ELF文件的
    PT\u LOAD
    部分生成一个原始文件。它可能需要是可执行的、可读写的(因为您将拥有代码和数据)。您可能需要准备一个指令,跳转到文件中间的入口点。

    您可能会看到
    ld.so
    是如何编译的:它应该被加载到虚拟地址空间中的任何位置,并且它本身有一个子集,在重新定位之前应该可以正常工作(因为
    ld.so
    按照我的理解重新定位自己)


    但您可能应该尝试实现一个基本的ELF加载程序(并正确处理重定位)。

    您可能可以做到这一点,但:

  • 您不能(通常)像在这里使用
    malloc
    那样将可执行文件存储在堆中(出于同样的原因,也不能存储在堆栈中),因为如果您的硬件支持它,您的操作系统可能会将这些区域标记为可读、可写但没有可执行文件(或者至少应该这样做)

  • 您不能只获取已编译程序的代码,将其提取到文件中,然后期望运行它,因为它通常需要重新定位、导入动态库、为变量设置另一个虚拟内存区域

  • 您可以通过一个简单的手工程序来实现这一点,该程序可以对
    exit(0)
    ot打印“Hello World”

    您可能能够使用编译后的代码。为此,您需要(至少):

    • 编译一个自包含程序(没有导入的动态库,静态链接库并重新编译静态链接库)

    • 带有位置独立代码(
      -fpic
      -fpie

    • 没有任何重新定位(可能有帮助吗?
      -fvisibility=hidden)

    如果您能够做到这一点,您可能能够从ELF文件的
    PT\u LOAD
    部分生成一个原始文件。它可能需要是可执行的、可读写的(因为您将拥有代码和数据)。而你可能需要p