【问题标题】:Is changing default virtual address in elf header to 0 possible?是否可以将 elf 标头中的默认虚拟地址更改为 0?
【发布时间】:2013-10-18 02:42:49
【问题描述】:

我可以将elf中的默认虚拟地址(ph_vaddr)更改为0x0吗?这将允许访问空指针吗?还是内核不允许在地址 0 加载?

我只想知道,如果我将某些部分的 p_vaddr 更改为 .text 为 0x0,linux 是否允许这样做?是否存在一些限制,虚拟地址只能在某个值之后开始?每当我尝试使用 ld --section-start 在 0 到 9999 之间的任何位置设置 .text vaddr 时,它都会被杀死。我想知道发生了什么事??

【问题讨论】:

  • 请解释一下你为什么问!!
  • 我正在阅读 elf 格式,然后我开始使用 p_vaddr 来更好地理解它。此时我迷路了,所以我来到了这里。

标签: linux elf


【解决方案1】:

我可以将精灵中的默认虚拟地址(ph_vaddr)更改为0x0吗?

是的,事实上PIE(位置无关)可执行文件通常是这样链接的。

echo "int main() { return 0; }" | gcc -xc - -fPIE -pie -o a.out
readelf -l a.out | grep LOAD | head -1

LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000

注意:上面生成了一个ET_DYN 类型的可执行文件。

这是否允许访问空指针?

没有。当内核发现可执行文件的.e_type == ET_DYN 时,它会将其所有段重新定位到其他地方。

您还可以使用.p_vaddr == 0 生成ET_EXEC 类型的可执行文件,如下所示:

echo "int main() { return 0; }" | gcc -xc - -o a.out -Wl,-Ttext=0
readelf -l a.out | grep LOAD | head -1
  LOAD           0x0000000000200000 0x0000000000000000 0x0000000000000000

内核会拒绝运行它:

./a.out
Killed

【讨论】:

  • 谢谢。这就回答了这个问题。
  • @EmployedRussian:“不。当内核发现可执行文件的第一个加载段的 .p_vaddr == 0 时,它会将其重新定位到其他地方。”可以? AFAIK,当 ELF 文件的类型为 ET_DYN 时,它会重新定位(至少这是 ELF 规范所期望的)。
  • @ysdx 我们正在讨论的PIE 二进制文件 ET_DYN,正如答案中已经讨论的那样。
  • @EmployedRussian,好的,那么它不会在所有情况下都重新定位吗?
  • @ysdx 我不明白你的问题。此评论线程也可能不是提出其他问题的地方。如果您有,请作为问题提出
【解决方案2】:

您可以在 mmap(2)MAP_FIXED 中使用以 (void*)0 开头的段,但我认为您不应该这样做。

我不知道更改elf(5) 中的虚拟地址是否会产生相同的效果。您是在谈论某个部分的p_vaddr 吗?

实际上,您真的不应该在 Linux 上的应用程序代码中使用 NULL 地址,尤其是如果其中一些代码是用 C 编码的,因为 NULL 指针具有非常特殊的含义,包括对编译器的含义。特别是,一些优化是基于NULL 不可取消引用的事实。

众所周知,GCC 确实会优化,例如,

 x = *p;
 if (!p) goto wasnull;

只是x= *p;,因为如果p已被取消引用,则它不能是NULL; GCC 对应用程序代码进行优化是正确的(而不是独立的)。

内核通常也在做Address Space Layout Randomization

【讨论】:

    猜你喜欢
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 2023-02-08
    相关资源
    最近更新 更多