22

我编写了一个小程序来添加两个整数,并在使用readelf -a executable_name它时将 elf 标头中的入口点地址显示为:

Entry point address: 0x8048330

即使在加载程序将其加载到内存中之前,我的可执行文件如何事先知道该地址? elf_format.pdf说这个成员给出了系统首先将控制权转移到的虚拟地址,从而启动了进程。谁能解释一下这个语句的含义以及这里的虚拟地址是什么意思?

还让我知道,可执行文件从哪里获取0x8048330作为入口点地址的值。只是为了交叉检查,我编译了另一个程序,为此,入口点地址保持相同的值(在这两种情况下,节的0x8048330偏移量)。.text0x330

4

3 回答 3

13

对于第一个问题:

您看到的入口点0x8048330是一个虚拟内存地址(相反,是物理内存)。这意味着您的主管不必知道要映射的物理地址。(使用加载器加载后)它甚至无法访问物理内存。对于您的程序进程,您的 .text 部分始终从 开始0x8048330,然后您的系统(操作系统和硬件)将在运行时将其(虚拟地址)映射到物理内存。

映射和管理物理内存是很多事情,您可以在 Google 上查看更多信息。

对于第二个问题

我不确定哪个部分让您感到困惑,所以我会尝试将它们全部覆盖:

  • 多个程序可以有相同的入口点吗?

是的,可能有另一个程序具有相同的入口点0x8048330。因为这个地址是虚拟的,当你试图同时运行它们时,程序会在运行时映射到不同的物理内存。

  • 条目总是0x8048330吗?

嗯,Linux 执行者是从 开始的0x8048000,但是 .text 节的偏移量与其他节的长度有关。所以不,它可能是0x8048034或其他任何东西。

  • 为什么总是从 开始0x8048000

我认为这是一种历史,Linux 的设计者出于某种未知甚至随机的原因选择了这个。您可以参考此线程以查看该区域下的内容。

于 2012-09-21T05:49:44.870 回答
13

入口地址由链接编辑器在创建可执行文件时设置。加载程序在将控制权转移到入口地址之前,将程序文件映射到 ELF 标头指定的地址。

要使用具体示例,请考虑以下内容:

% file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, \
    for GNU/Linux 2.6.15, not stripped
% readelf -e a.out
... snip ...
Elf file type is EXEC (Executable file)
Entry point 0x8048170
There are 6 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x7cca6 0x7cca6 R E 0x1000
  LOAD           0x07cf98 0x080c5f98 0x080c5f98 0x00788 0x022fc RW  0x1000
... snip ...

第一个程序头指定文件偏移量 0 处的文件内容应映射到虚拟地址 0x08048000。该段的文件和内存大小为 0x7cca6 字节。该段将被映射为可读和可执行但不可写(它包含程序的代码)。

在 ELF 头中指定的入口点地址是 0x8048170,它位于包含程序代码的区域内。

John Levine所著的“ Linkers and Loaders ”一书是一个很好的参考链接编辑器和加载器相关问题的资源。

于 2012-09-19T19:16:22.167 回答
3

关于虚拟地址问题:

普通用户态应用程序使用虚拟地址,这意味着它们不直接访问内存空间。操作系统(借助一些微处理器的特殊功能)将此虚拟地址映射到物理地址

这样,操作系统可以防止应用程序读取/写入其他应用程序内存或操作系统保留内存。此外,这允许以透明的方式为应用程序分页内存(使用硬盘作为内存)。

于 2012-09-19T08:54:25.677 回答