基本汇编程序出现“非法指令”错误——甚至不是hello world——为什么需要链接?

3
我刚刚想通了,不必将我的新问题(“为什么?”)拆分为另一个问题,我认为最好的解决方案是将此问题的解决方案和解释放在同一页上。
我正在编写一个基本的汇编程序,只是使用内核中断int 0x80启动并立即退出。我的当前代码如下:
/* Simple exit via kern-interrupt */

.globl start

start:
    pushl $0x0
    movl $0x1, %eax
    subl $4, %esp
    int $0x80

使用组装

as -arch i386 <file>.s

执行时出现一行错误提示:
Illegal instruction

这太奇怪了,即使把所有内容都注释掉,结果仍然是 "非法指令",尽管根本没有任何指令。我是否错过了一个 "链接" 步骤,尽管没有其他文件需要链接?是的,我错过了

编辑:请允许我重新表达我的问题,为什么在没有库或任何需要链接的情况下还需要链接?

2个回答

3

您需要将它链接起来才能创建可执行文件。默认情况下,as 只会给您提供一个对象文件,这是一个可以与其他对象文件链接成为可执行文件的文件(或者单独使用),但它本身不是一个有效的可执行文件。尝试:

as -arch i386 -o file.o file.s
ld -o file file.o

针对您的问题:

为什么没有库或其他需要连接时,你需要链接?

因为汇编程序不知道您是否会与其他内容进行链接。

gcc 编译器不同,后者会默认认为您要生成一个程序,除非使用 -c 选项告知其不生成程序。而 as 编译器默认生成目标文件。根据手册描述:

"as" 主要用于汇编 GNU C 编译器 "gcc" 的输出,以便供链接器 "ld" 使用

如果您想要一步完成操作,您可以创建一个名为 asld 的脚本:

as -arch i386 -o $1.o $1.s
ld -o $1 $1.o

然后只需使用asld file命令即可。

或者,您可以设置makefile来帮助您完成所有繁重的工作。


如果它只是一个对象文件,会有什么区别呢? - Hawken
@Hawken,你不能运行一个目标文件,就像你不能运行或链接源文件或编译数据库索引一样 :-) 目标文件是一种准备好被链接到可执行文件中的形式,但它本身不是可执行文件。 - paxdiablo
那么链接器添加的神秘代码是什么?我在 hexdump 中看到的文件大小几乎翻了一倍。前十二个字节是相同的。 - Hawken
那将是“链接器添加的神秘代码”,换句话说,它想要什么就加上什么 :-) 最有可能的是额外的信息,用于使程序运行,例如ELF信息、堆栈信息等等。像readelf这样的程序可以解码它。 - paxdiablo
2
你可以_尝试_使用http://sourceforge.net/projects/machoview/,但我从未使用过它。 - paxdiablo

1

对于C程序,你也可以使用同样的论点,我没有使用任何库,为什么我必须链接呢?

因为工具链就是这样设计的。一组工具将源代码(任何/许多语言)转换为大部分时间不完整的目标文件。即使像paxdiablo所示的那样,链接阶段只需将您的目标文件变成可执行文件,它也是必需的。如果没有其他的东西,你的.text地址(通常)是需要的,这来自于链接器阶段。

按照这种方式做是有很多道理的,链接阶段已经够复杂了,让一个完成这项工作并擅长这项工作的工具去做。进行系统工程,并定义与该工具的接口。语言工具有一个复杂的工作要做,让它们只做那个工作,输出一个目标文件,这是它们可以解决的最远距离,而无需成为链接器。

如果你不想使用这个工具链,可能会使用nasm或类似的工具,在一条命令行步骤中直接从汇编到二进制。


据我所知,即使你不想使用标准库,普通的 C 程序也会使用它。这就是为什么 C 转换成汇编语言时不包括内核中断,并且返回被某个神秘代码调用的 _main 子例程。该子例程与 C 程序链接在一起。 - Hawken
取决于您对“正常C程序”的定义。就像这个ASM程序一样,您可以编写不使用任何库和除编译版本的C代码之外的东西的C代码,但编译后的版本将进入链接的二进制文件中。main()甚至不是必需的(某些gnu工具的某种flavor _start)。大多数C程序,几乎全部,肯定会做一些有趣/有用的事情,并需要C库或希望在操作系统上运行并需要一些启动代码才能运行main(),或者有许多其他原因需要链接项目。 - old_timer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接