LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1112|回复: 13

ld 的 -e 参数求解

[复制链接]
发表于 2005-4-4 22:04:40 | 显示全部楼层 |阅读模式
-e 参数应该是用来显式的指定程序入口的,但是好像事实并非如此
实验如下:
a.s
.global:a a:movl %eax,%eax
b.s
.global:b b:movl %ebx,%ebx
c.s
.global:c c:movl %ecx,%ecx

as a.s -o a.o ; as b.s -o b.o ; as c.s -o c.o
ld a.o b.o c.o -o out -e b --oformat binary -Ttext 0x0
ndisasm out

输出:
00000000  89C0              mov ax,ax
00000002  89D2              mov dx,dx
00000004  89DB              mov bx,bx
00000006  90                nop
00000007  90                nop
00000008  89C9              mov cx,cx

很显然,入口不是b,而是在ld中出现的第一个文件的第一个指令(当然,如果不是指令,也将其作为指令解释),
发表于 2005-4-5 12:06:22 | 显示全部楼层
Post by rickxbx
-e 参数应该是用来显式的指定程序入口的,但是好像事实并非如此
。。。。。。
很显然,入口不是b,而是在ld中出现的第一个文件的第一个指令(当然,如果不是指令,也将其作为指令解释),

口气怎么这么肯定呀?ld被人使用了这么多年,如果真的有问题也早就被debug光了。
事实与理论不符合时,是先怀疑理论不正确,还是仔细想想自己在什么地方做错了?
通常情况下,一般都是自己做错了。因为理论是经过了很多人很多次实践的检验的,真的要是有错误,也早就被别人发现了。轮到你去发现新大陆的机会是极少极少的。
OK,回到正题:
程序通常不会按照指令存贮的顺序逐条执行的,在一个地方可以用跳转指令转移到另一个地方执行。在你的程序中虽然b.o在链接时没有被放在前面,但在可执行文件中,程序执行入口点的地址是由ELF的段头表决定的。看看下面readelf的结果:

  1. bash-2.05b$ objdump -d a.out

  2. a.out:     文件格式 elf32-i386

  3. 反汇编 .text 节:

  4. 08048094 <a>:
  5. 8048094:       89 c0                   mov    %eax,%eax
  6. 8048096:       90                      nop
  7. 8048097:       90                      nop

  8. 08048098 <b>:
  9. 8048098:       89 db                   mov    %ebx,%ebx
  10. bash-2.05b$ readelf -h a.out
  11. ELF 头:
  12.   Magic:  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  13.   Class:                             ELF32
  14.   Data:                              2's complement, little endian
  15.   Version:                           1 (current)
  16.   OS/ABI:                            UNIX - System V
  17.   ABI Version:                       0
  18.   Type:                              EXEC (可执行文件)
  19.   Machine:                           Intel 80386
  20.   Version:                           0x1
  21.   入口点地址:              0x8048098
  22.   程序头起点:              52 (bytes into file)
  23.   Start of section headers:          200 (bytes into file)
  24.   标志:             0x0
  25.   本头的大小:       52 (字节)
  26.   程序头大小:       32 (字节)
  27.   程序头数量:       3
  28.   节头大小:         40 (字节)
  29.   节头数量:         7
  30.   字符串表索引节头: 4
  31. bash-2.05b$
复制代码

入口点地址不就是b.o被链接后的地址吗?!!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-4-5 13:02:09 | 显示全部楼层
Post by kj501
口气怎么这么肯定呀?ld被人使用了这么多年,如果真的有问题也早就被debug光了。
事实与理论不符合时,是先怀疑理论不正确,还是仔细想想自己在什么地方做错了?
通常情况下,一般都是自己做错了。因为理论是经过了很多人很多次实践的检验的,真的要是有错误,也早就被别人发现了。轮到你去发现新大陆的机会是极少极少的。
OK,回到正题:
程序通常不会按照指令存贮的顺序逐条执行的,在一个地方可以用跳转指令转移到另一个地方执行。在你的程序中虽然b.o在链接时没有被放在前面,但在可执行文件中,程序执行入口点的地址是由ELF的段头表决定的。看看下面readelf的结果:

  1. bash-2.05b$ objdump -d a.out

  2. a.out:     文件格式 elf32-i386

  3. 反汇编 .text 节:

  4. 08048094 <a>:
  5. 8048094:       89 c0                   mov    %eax,%eax
  6. 8048096:       90                      nop
  7. 8048097:       90                      nop

  8. 08048098 <b>:
  9. 8048098:       89 db                   mov    %ebx,%ebx
  10. bash-2.05b$ readelf -h a.out
  11. ELF 头:
  12.   Magic:  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  13.   Class:                             ELF32
  14.   Data:                              2's complement, little endian
  15.   Version:                           1 (current)
  16.   OS/ABI:                            UNIX - System V
  17.   ABI Version:                       0
  18.   Type:                              EXEC (可执行文件)
  19.   Machine:                           Intel 80386
  20.   Version:                           0x1
  21.   入口点地址:              0x8048098
  22.   程序头起点:              52 (bytes into file)
  23.   Start of section headers:          200 (bytes into file)
  24.   标志:             0x0
  25.   本头的大小:       52 (字节)
  26.   程序头大小:       32 (字节)
  27.   程序头数量:       3
  28.   节头大小:         40 (字节)
  29.   节头数量:         7
  30.   字符串表索引节头: 4
  31. bash-2.05b$
复制代码

入口点地址不就是b.o被链接后的地址吗?!!


呵呵,这位仁兄貌似在说教.在下承认你说的没错.
这里有个可执行文件的概念在里面可你有没有注意到我在使用ld的时候给的参数是--oformat binary,这样生成的是raw binary,而并不是elf文件格式,elf格式只有特定操作系统才认识,比如,linux(比较新的,以前是a.out).一般情况下,我们所说的可执行文件,都是指elf文件.正如阁下所说,这种文件格式有个elf header,当然如果是可执行格式的话,还应该有个program header,right?但现在我并不是要得到elf文件,而是raw binary,是操作系统无关的可执行文件(当然也可以说是可执行代码)

好了,我也言归正传了:所以我个人想法是.是不是ld 的这个参数(-e)只适用于被操作系统加载的可执行程序?  当然,也有可能有些地方没注意到,但绝不是elf文件格式所能解释的
回复 支持 反对

使用道具 举报

发表于 2005-4-5 21:38:50 | 显示全部楼层
除了内核和bootloader,其它所有程序都要在操作系统支持下执行。程序在被执行时,是由操作系统中的加载器(loader)加载的。为了保证程序正确运行,加载器需要进行一系列的进程运行环境设置工作,比如说对数据段,正文段的加载和设置,初始化堆栈段等等,进行这些工作所需要的信息如数据段的长度和按多少字节对齐等等,就需要由可执行文件提供。这就是由操作系统加载的程序需要有一个可执行文件格式的原因。如果你的可执行文件是一个不能提供这些信息的raw binary,一定会被操作系统拒绝执行。程序执行的入口点也是由加载器根据可执行文件中提供的信息来设置的。ld -e就是起这个作用。
我感觉你的意思好象是要链接出一种不依赖于操作系统可以直接在任何平台上直接运行的二进制可执行文件,除了内核和bootloader,这是不可能的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-4-6 09:14:49 | 显示全部楼层
Post by kj501
除了内核和bootloader,其它所有程序都要在操作系统支持下执行。程序在被执行时,是由操作系统中的加载器(loader)加载的。为了保证程序正确运行,加载器需要进行一系列的进程运行环境设置工作,比如说对数据段,正文段的加载和设置,初始化堆栈段等等,进行这些工作所需要的信息如数据段的长度和按多少字节对齐等等,就需要由可执行文件提供。这就是由操作系统加载的程序需要有一个可执行文件格式的原因。如果你的可执行文件是一个不能提供这些信息的raw binary,一定会被操作系统拒绝执行。程序执行的入口点也是由加载器根据可执行文件中提供的信息来设置的。ld -e就是起这个作用。


你说的亦没错,

Post by kj501

我感觉你的意思好象是要链接出一种不依赖于操作系统可以直接在任何平台上直接运行的二进制可执行文件,除了内核和bootloader,这是不可能的。


但你的感觉错了,我所讨论的是普遍情况,即 ld 的 -e 参数是不是普适,还是只对需要加载的可执行文件适用(关于这一点,在上面的帖子中我已经指明).事实上,我所关注的就是这里的临界,因为以前的工作不涉及内核的具体细节,而现在的工作却是要实现一个操作系统内核.所以对这里的临界想做点了解.

ps:到现在为止,你还没给我个答案,-e 选项究竟是否普适? 个人感觉,貌似不普适.还是上面的话,有可能有些地方我没有注意到,所以请教各位达者.

ps:斑竹说的其实都是正确的,只是并不是我所需要的答案.所以继续请教中......
回复 支持 反对

使用道具 举报

发表于 2005-4-6 10:42:16 | 显示全部楼层
对于纯的二进制,ld的e是没什么用的,连接时谁在前面谁就是入口地址。个人经验,供参考。
回复 支持 反对

使用道具 举报

发表于 2005-4-6 10:47:11 | 显示全部楼层
你所说的“临界”是什么意思?“普适”的范围又如何界定?
对于这些模糊词汇,我始终搞不清楚它们的含义。

我其实已经说得很清楚了,一个程序总有一个执行入口地址。这个执行入口地址如果不在链接时用ld -e指定,那它就只能事先约定入口执行地址在什么地方,当然同时也得约定程序的加载位置。对于raw binary,得由加载它的程序决定。加载它的程序决定从头开始执行,就从头开始执行。如果加载它的程序要从文件的中间开始执行,从逻辑上说,也没有任何问题。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-4-6 12:21:09 | 显示全部楼层
Post by lgj1107
对于纯的二进制,ld的e是没什么用的,连接时谁在前面谁就是入口地址。个人经验,供参考。

呵呵,这也是我的经验.

事实上,我要的就是这样一针见血的回帖."是"或者"不是",或者其他什么的,而不是从另一个角度说,而回避问题

ps:如果有文档支持这种说法就更好了
回复 支持 反对

使用道具 举报

发表于 2005-4-6 19:13:46 | 显示全部楼层
Post by rickxbx
呵呵,这也是我的经验.

事实上,我要的就是这样一针见血的回帖."是"或者"不是",或者其他什么的,而不是从另一个角度说,而回避问题

ps:如果有文档支持这种说法就更好了

我什么时候回避问题了?!!
你看看你的提的第一个问题,先不说清楚问题的背景,一上来就说ld -e不能指定程序的入口地址,我当然要反驳你的意见啦。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-4-6 21:16:14 | 显示全部楼层
Post by kj501
我什么时候回避问题了?!!
你看看你的提的第一个问题,先不说清楚问题的背景,一上来就说ld -e不能指定程序的入口地址,我当然要反驳你的意见啦。

呵呵,不用火,不用火
如果仔细看我给的程序就明白了,我用了 --oformat binary ,还有 ndisasm 而不是 objdump,应该差不多能明白了

ps:我说你回避问题,主要是指的后面回帖,而不是一开始的反驳.后来的帖子中,为了消除各位的误解,我就强调了我所讨论的是 raw binary,而不是我们通常意义上的elf可执行文件

ps:讨论问题,增长知识才是最主要的,你说是吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表