我可以将elf中的默认虚拟地址(ph_vaddr)更改为0x0。这会允许访问空指针??或者内核不允许加载地址0?
我只是想知道,如果我将某些部分的p_vaddr更改为.text为0x0,linux是否允许这样做?是否存在一些约束,即虚拟地址只能在某个值之后才能启动?每当我尝试使用ld --section-start设置.text vaddr时,它会在0到9999之间的任何地方被杀死。我想知道发生了什么事?
答案 0 :(得分:2)
我可以将elf中的默认虚拟地址(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
时,它会将其所有段重新定位到其他位置。
您还可以使用ET_EXEC
制作.p_vaddr == 0
类型的可执行文件,如下所示:
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
答案 1 :(得分:0)
您可以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。