我正在学习汇编编程。下面是打印“Hello, World!”的简单程序。当程序完美运行时,我收到警告消息,而 loading
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
这是代码:
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
section .text
global main
main:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
任何人都可以解释这个警告的含义。我正在使用
nasm
与 ubuntu 14
.
最佳答案
使用标签 _start
而不是 main
用于 ELF 入口点。 main
暗示它就像 C main
函数,但这甚至不是函数(例如 you can't ret
)。
您没有说,但是从错误消息和代码中,我假设您正在使用 nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
构建 32 位代码
(如果您实际上正在构建 64 位代码,那么您很幸运它恰好可以工作,但是一旦您使用 esp
而不是 rsp
进行任何操作,它就会中断。)
错误信息来自 ld
,而不是来自 nasm
.它在消息中说得对。蒂姆的评论是正确的:ld
寻找 _start
符号在它链接的文件中,但如果找不到,则将入口点设置为文本段的开头。
您定义的其他全局/外部符号无关紧要。 main
在这里根本没有相关性,并且可以指向您想要的任何地方。它只对反汇编输出和类似的东西有用。如果您取出 global main
,您的代码将完全相同。/main:
行,或将它们更改为任何其他名称。
将其标记为 main
是不明智的,因为 ELF 入口点不是函数 .这不是 main()
,并且没有收到 argc
和 argv
参数,并且不能 ret
因为 ESP 指向 argc
而不是返回地址。
仅使用 main
如果你链接 gcc/glibc 的 CRT 启动代码,它会寻找 main
符号并在初始化 libc 后调用它。 (所以像 printf 这样的函数可以工作。技术上动态的链接器钩子(Hook)让 libc 在你的 _start
之前自行初始化,如果你链接了它,但通常不要这样做,除非你完全理解你在做什么)。相关:Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
例如 gcc -m32 -no-pie -o hello main.o
如果您确实定义了 main:
而不是 gcc -m32 -static -nostdlib -o hello start.o
(相当于你的裸 ld
)。
(在过去的几年里,Linux 发行版有 configured GCC with -pie
as the default ,它需要与位置无关的代码。但是在没有 RIP 相对寻址的 32 位模式下,这真的很不方便(例如,查看 GCC asm 输出),这意味着 ld
不会为您将 call printf
转换为 call printf@plt
。因此,对于大多数遵循大多数教程的手写 asm,您需要传统的非 PIE 可执行文件,因此不需要文本重定位。)
关于linux - 加载警告 : cannot find entry symbol _start,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34758769/