跟踪Why is the ELF execution entry point virtual address of the form 0x80xxxxx and not zero 0x0?和Why do virtual memory addresses for linux binaries start at 0x8048000?,为什么我不能让ld
使用与默认ld -e
不同的入口点?
如果这样做,我要么得到一个返回代码139的segmentation fault
,即使是在默认入口点关闭的地址。为什么?
编辑:
我会提出更具体的问题:
.text
.globl _start
_start:
movl $0x4,%eax # eax = code for 'write' system call
movl $1,%ebx # ebx = file descriptor to standard output
movl $message,%ecx # ecx = pointer to the message
movl $13,%edx # edx = length of the message
int $0x80 # make the system call
movl $0x0,%ebx # the status returned by 'exit'
movl $0x1,%eax # eax = code for 'exit' system call
int $0x80 # make the system call
.data
.globl message
message:
.string "Hello world\n" # The message as data
如果我用as program.s -o program.o
编译它,然后将它静态地链接到ld -N program.o -o program
,readelf -l program
显示0x0000000000400078
作为文本段的VirtAddr
,0x400078
作为入口点。运行时,打印“”。
但是,当我试图链接到ld -N -e0x400082 -Ttext=0x400082 program.o -o program
(移动文本段和入口点4字节)时,程序将是killed
。用readelf -l
检查它现在显示了LOAD
类型的两个不同的头,一个在0x0000000000400082
,一个在0x00000000004000b0
。
当我尝试0x400086
时,它都能工作,而且只有一个LOAD
部分。
谢谢你。
发布于 2011-11-13 21:41:34
为什么我不能让ld使用与默认的ld -e不同的入口点?
你当然可以。这是:
int foo(int argc, char *argv[]) { return 0; }
gcc main.c -Wl,-e,foo
不起作用,因为执行不是从main开始的。它从_start
开始,它是从crt0.o
(glibc的一部分)链接起来的,并安排诸如动态链接等的事情来正确地启动。通过将_start
重定向到foo
,您已经绕过了所有所需的glibc初始化,因此无法工作。
但是,如果您不需要动态链接,并且愿意做glibc通常为您做的事情,那么您可以随意命名入口点。示例:
#include <syscall.h>
int foo()
{
syscall(SYS_write, 1, "Hello, world\n", 13);
syscall(SYS_exit, 0);
}
gcc t.c -static -nostartfiles -Wl,-e,foo && ./a.out
Hello, world
哦,这个问题的标题和你的实际问题不匹配(坏主意(TM))。
要回答标题中的问题,您肯定可以更改可执行文件链接到的地址。默认情况下,您将获得0x8048000
加载地址(仅以32位为单位;64位默认值为0x400000
)。
通过将0x80000
添加到链接行中,您可以轻松地将其更改为例如-Wl,-Ttext-segment=0x80000
。
更新:
,但是,当我试图链接到ld -N -e0x400082 -Ttext=0x400082 program.o -o程序(将文本段和入口点移动4个字节)时,程序将被终止。
不可能在不违反Ttext
节对齐约束(即4)的情况下将0x400082
分配给.text
。必须在至少4字节的边界上保持.text地址对齐(或更改.text
所需的对齐方式)。
当我将起始地址设置为0x400078、0x40007c、0x400080、0x400084、.、0x400098并使用GNU 2.20.1时,程序就可以工作了。
但是,当我使用binutils的当前CVS快照时,该程序工作于0x400078、0x40007c、0x400088、0x40008c,并因0x400080、0x400084、0x400090、0x400094、0x400098而被杀死。这可能是链接器中的一个bug,或者我违反了其他一些约束(我看不出是哪个)。
在这一点上,如果您真的感兴趣,我建议下载二进制文件源代码,构建ld
,并找出究竟是什么原因导致它创建两个PT_LOAD
段而不是一个。
更新2:
强制新的区段与重叠的LMA。
阿!这就意味着你需要把.data
移开。这使得一个工作的可执行文件:
ld -N -o t t.o -e0x400080 -Ttext=0x400080 -Tdata=0x400180
https://stackoverflow.com/questions/8116648
复制相似问题