【问题标题】:Why is the program header executable?为什么程序头是可执行的?
【发布时间】:2019-01-06 22:13:08
【问题描述】:

我在我的 linux 机器上的几个二进制文件上使用了 readelf,并在程序头文件中看到了令我惊讶的东西。此示例来自 'ld' 实用程序,但它也发生在我使用 gcc 编译的任何内容中。

PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4

此段跨越整个程序头。为什么被标记为可执行?它不包含机器代码。而且,为什么标题中还会出现这个?我真的不希望它出现在我的程序图像中。

【问题讨论】:

    标签: linux elf


    【解决方案1】:

    指向 PHDR 的 PHDR 告诉加载器 PHDR 本身应该映射到进程地址空间,以便程序本身可以访问它们。

    这主要用于动态链接。

    内存被标记为可执行的原因是因为 PHDR 小于一页,并且位于可执行代码开头的旁边。如果 PHDR 的权限与程序文本的权限不同,则链接器必须在它们之间插入填充。

    【讨论】:

    • 这是在加载时还是在运行时?我猜如果它在运行时 gcc 可能不够聪明,无法确定没有执行运行时库加载。
    • 它也没有解释为什么这个内存应该是可执行的。
    • 程序链接的任何动态库都可以替换为动态加载插件的版本,因此动态链接的程序将始终能够在执行期间加载共享对象,因此需要存在 PHDR .
    • 内存是可执行的,因为 PHDR 小于一页,并且位于可执行代码的开头。如果 PHDR 的权限与程序文本的权限不同,则链接器必须在它们之间插入填充。
    • 啊哈。这终于开始有意义了。
    【解决方案2】:

    主要的文件 ELF 标头可以轻松找到存储其他部分的文件中的偏移量。然后每个子标题描述其部分中的数据。

    主 ELF 标头如下所示:

    /* ELF File Header */
    typedef struct
    {
      unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
      Elf32_Half    e_type;                 /* Object file type */
      Elf32_Half    e_machine;              /* Architecture */
      Elf32_Word    e_version;              /* Object file version */
      Elf32_Addr    e_entry;                /* Entry point virtual address */
      Elf32_Off     e_phoff;                /* Program header table file offset */
      Elf32_Off     e_shoff;                /* Section header table file offset */
      Elf32_Word    e_flags;                /* Processor-specific flags */
      Elf32_Half    e_ehsize;               /* ELF header size in bytes */
      Elf32_Half    e_phentsize;            /* Program header table entry size */
      Elf32_Half    e_phnum;                /* Program header table entry count */
      Elf32_Half    e_shentsize;            /* Section header table entry size */
      Elf32_Half    e_shnum;                /* Section header table entry count */
      Elf32_Half    e_shstrndx;             /* Section header string table index */
    } Elf32_Ehdr;
    

    程序头在那里是因为它们描述了 ELF 可执行文件的可执行部分。

    程序的下一部分是 ELF 程序头文件。这些 描述程序的各个部分 包含可执行程序代码 映射到程序地址 加载时的空间。

    /* Program segment header.  */
    
    typedef struct
    {
      Elf32_Word    p_type;                 /* Segment type */
      Elf32_Off     p_offset;               /* Segment file offset */
      Elf32_Addr    p_vaddr;                /* Segment virtual address */
      Elf32_Addr    p_paddr;                /* Segment physical address */
      Elf32_Word    p_filesz;               /* Segment size in file */
      Elf32_Word    p_memsz;                /* Segment size in memory */
      Elf32_Word    p_flags;                /* Segment flags */
      Elf32_Word    p_align;                /* Segment alignment */
    } Elf32_Phdr;
    

    这取自here

    【讨论】:

    • 我知道他们为什么在那里。我在问为什么有一个程序头,告诉我们头在哪里。如果您可以阅读标题,那么您已经知道在哪里看。
    • @eye:有上面提到的程序头,还有主文件ELF头,其中包含对所有子头的引用。你说的是那个吗?
    • 不存在一个程序头,它定义了一个覆盖整个程序头集的段。试试 readelf -l /bin/ls
    • @eye:我在任何地方都找不到 ELF 格式的描述?
    猜你喜欢
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 2019-02-28
    相关资源
    最近更新 更多