我可以将elf中的默认虚拟地址(ph_vaddr)更改为0x0吗?这将允许访问空指针吗?还是内核不允许在地址 0 加载?
我只想知道,如果我将某些部分的 p_vaddr 说 .text 更改为 0x0,linux 是否允许这样做?是否存在一些限制,虚拟地址只能在某个值之后开始?每当我尝试使用 ld --section-start 在 0 到 9999 之间的任何位置设置 .text vaddr 时,它都会被杀死。我想知道这是怎么回事??
我可以将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
您可以mmap(2)开始MAP_FIXED
的段,(void*)0
但我认为您不应该这样做。
我不知道改变elf(5)中的虚拟地址是否会做同样的事情。你说的p_vaddr
是某个细分市场吗?
实际上,您真的不应该NULL
在 Linux 上的应用程序代码中使用地址,尤其是如果其中一些代码是用 C 编码的,因为NULL
指针具有非常特殊的含义,包括对编译器的含义。特别是,一些优化是基于NULL
不可取消引用的事实进行的。
众所周知,GCC 确实进行了优化,例如,
x = *p;
if (!p) goto wasnull;
into 只是x= *p;
因为 ifp
已被取消引用,它不能是NULL
; GCC 对应用程序代码进行优化是正确的(而不是独立的)。