从_start调用printf时出现链接器错误 [英] Linker error when calling printf from _start

查看:228
本文介绍了从_start调用printf时出现链接器错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写没有 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:

所有打开的stdio(3)流都被刷新并关闭.由tmpfile(3)创建的文件将被删除.

All open stdio(3) streams are flushed and closed. Files created by tmpfile(3) are removed.

我建议将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时出现链接器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆