我正在学习汇编编程。下面是一个简单的程序,它打印“Hello,World!”。虽然程序运行得很好,但我在loading
ld:警告:找不到项symbol _start;默认为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
一起使用。
7条答案
按热度按时间k5hmc34c1#
使用标签
_start
代替main
做为ELF进入点。main
表示它类似于Cmain
函式,但这什至不是函式(例如you can'tret
)。你没说,但是从警告消息和代码来看,我假设你正在用
nasm -felf32 hello32.asm && ld -melf_i386 -o hello32 hello32.o
构建32位代码(If您实际上是在构建64位代码,幸运的是它恰好可以工作,但只要您使用
esp
而不是rsp
执行任何操作,它就会崩溃。)警告消息来自
ld
,而不是来自nasm
。消息中有这样的说明。Tim的注解是正确的:ld
在它所链接的文件中查找_start
符号,但如果没有找到,则将入口点设置为文本段的开头。(这就是为什么这是一个警告,而不是错误。如果您在文件的前面放置了一些其他代码,则执行将在没有global _start
/_start:
的情况下从那里开始)不管你定义了什么其他的全局/外部符号。
main
在这里没有任何相关性,可以指向任何你想要的地方。它只对反汇编输出和类似的东西有用。如果你去掉global main
/main:
行,或者把它们改成任何其他名称,你的代码会完全一样地工作。将其标记为
main
是不明智的,因为ELF入口点 * 不是函数*。它 * 不是 *main()
,并且不以标准方式接收argc
和argv
参数,也不能接收ret
,因为ESP指向argc
而不是返回地址。只有当您链接gcc / glibc的CRT启动代码时,才使用
main
,gcc/ glibc的CRT启动代码会查找main
符号,并在初始化libc后调用它。(因此printf之类的函数可以工作。从技术上讲,如果您链接了libc,动态链接器钩子会让libc在您的_start
之前初始化它自己,但通常不会这样做,除非您完全理解您在做什么)。Assembling 32-bit binaries on a 64-bit system (GNU toolchain)例如,如果您定义了
main:
,则为**gcc -m32 -no-pie -o hello main.o
**而不是
gcc -m32 -static -nostdlib -o hello start.o
(相当于你的裸
ld
)。(For过去几年,Linux发行版提供了configured GCC with
-pie
as the default,它需要位置无关的代码,但在32位模式下,这确实很不方便,因为在32位模式下,您没有x86-64 RIP相对寻址(例如查看GCC asm输出),并且意味着ld
不会为您将call printf
转换为call printf@plt
。因此对于大多数教程中的大多数手写asm,您需要传统的非PIE可执行文件,因此不需要文本重定位。)wgxvkvu92#
我建议您将对象文件(无论它们是如何生成的)与
gcc
链接,而不是与ld
链接。gcc
将使用适当的选项调用ld
,因为它知道更多关于源代码的信息,并将创建ld
所做假设所需的任何内容。tsm1rwdh3#
我不知道这是否是一个有效的修复,但似乎对我有效:
尝试使用选项
同时链接内核C代码。
djp7away4#
您可以尝试使用 nasm 编译组件原始程式档,产生 *.o档,然后使用 ld 以参数 *-e main链接 .o档。 这表示main会指定为程式项目。
nbnkbykc5#
您应该使用_start而不是main来指示nasm汇编程序应该从何处开始执行。例如:
idv4meu86#
要编译和执行程序,您可以创建
bash
脚本,如下所示:compile64.sh
jaxagkaj7#
在你的程序中有一些问题,比如一些语法错误,比如你不能把寄存器的值赋给常量,因为常量不能保存任何值,为了存储常量值,我们使用变量
虽然组装你的程序,我得到下面提到的asseble时间错误
无此类说明:
msg db 72ello,world!440xa' assign.S:3: Error: no such instruction:
透镜设备$ -消息分配。S:4:错误:没有此指令:section .text' assign.S:5: Error: no such instruction:
全局主“分配。S:7:错误:mov' assign.S:8: Error: too many memory references for
mov' assign的内存引用太多。S:9:错误:mov' assign.S:10: Error: too many memory references for
mov' assign的内存引用太多。S:11:错误:int' assign.S:12: Error: too many memory references for
mov' assign的操作数大小不匹配。S:13:错误:'int'的算子大小不符下面的代码在32位英特尔处理器的gnu编译器上也给予相同的输出。
.段.记录数据消息GP:.string“您好,世界”
保存这段代码,最新的名字是Hello.S asseble,用$ as -o Hello.o Hello.S链接,用$ ld -o Hello.o -lc -dynamic-linker/lib.ld.linux.so.2 -e main -Hello.o运行$ ./Hello
我希望这对你有帮助