问题描述
我尝试编写没有 main
segment .data
fmt db "test", 0xa, 0
segment .text
global _start
extern printf
_start:
lea rdi, [fmt] ; print simple string
xor eax, eax
call printf
mov eax, 60 ; exit successfully
xor edi, edi
syscall
编译:
yasm -f elf64 main.s; ld -o main main.o
知道了
main.o: In function `_start':
main.s:(.text+0xb): undefined reference to `printf'
应该如何解决?
推荐答案
错误原因
链接时得到undefined reference to printf
的原因是因为您未针对 C 库进行链接.同样,当使用自己的_start
标签作为切入点时,还必须解决其他问题,如下所述.
Cause of Your Error
The reason you get undefined reference to printf
while linking is because you didn't link against the C library. As well, when using your own _start
label as an entry point there are other issues that must be overcome as discussed below.
要确保在运行时使用适当的动态链接器并链接到 C 库,可以将 GCC 用作 LD .要提供自己的_start
标签并避免使用 C 运行时启动代码,请使用-nostartfiles
选项.尽管我不推荐这种方法,但是您可以链接:
To make sure you are using the appropriate dynamic linker at runtime and link against the C library you can use GCC as a frontend for LD. To supply your own _start
label and avoid the C runtime startup code use the -nostartfiles
option. Although I don't recommend this method, you can link with:
gcc -m64 -nostartfiles main.o -o main
如果您希望使用 LD ,则可以通过使用特定的动态链接器并使用-lc
链接到 C 库来实现.要链接x86_64代码,您可以使用:
If you wish to use LD you can do it by using a specific dynamic linker and link against the C library with -lc
. To link x86_64 code you can use:
ld -melf_x86_64 --dynamic-linker=/lib64/ld-linux-x86-64.so.2 main.o -lc -o main
如果您一直在为32位进行编译和链接,则可以使用以下方式完成链接:
If you had been compiling and linking for 32-bit, then the linking could have been done with:
ld -melf_i386 --dynamic-linker=/lib/ld-linux.so.2 main.o -lc -o main
使用C运行时启动代码的首选方法
由于使用的是 C 库,因此应考虑链接 C 运行时.如果要创建静态可执行文件,此方法也可以使用.使用 C 库的最佳方法是将_start
标签重命名为main
,然后使用 GCC 链接:
Preferred Method Using C Runtime Startup Code
Since you are using the C library you should consider linking against the C runtime. This method also works if you were to create a static executable. The best way to use the C library is to rename your _start
label to main
and then use GCC to link:
gcc -m64 main.o -o main
以这种方式执行操作可以使您通过从main
返回(使用 RET )(与 C 程序结束相同的方式)退出程序.这样做还具有在程序退出时刷新标准输出的优点.
Doing it this way allows you to exit your program by returning (using RET) from main
the same way a C program ends. This also has the advantage of flushing standard output when the program exits.
使用 EAX = 60的syscall
退出不会刷新输出缓冲区.因此,您可能发现自己必须在输出中添加换行符才能在退出之前查看输出.这仍然不能保证您将看到使用printf
输出的内容.您可以考虑调用 C 库函数exit
,而不是sys_exit SYSCALL . exit
的 MAN PAGE 说:
Using syscall
with EAX=60 to exit won't flush the output buffers. Because of this you may find yourself having to add a newline character on your output to see output before exiting. This is still not a guarantee you will see what you output with printf
. Rather than the sys_exit SYSCALL you might consider calling the C library function exit
. the MAN PAGE for exit
says:
我建议将sys_exit SYSCALL 替换为:
I'd recommend replacing the sys_exit SYSCALL with:
extern exit
xor edi, edi ; In 64-bit code RDI is 1st argument = return value
call exit
这篇关于从_start调用printf时出现链接器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!