如何使用'ld'链接C运行时库?

13

我正在为大学课程学习使用NASM汇编语言。 我想要用ld链接C Runtime Library,但我似乎无法理解它。我使用的是安装了Linux Mint64位计算机。

我感到困惑的原因是,据我所知,gcc不是链接C运行时库,而是将需要的内容复制到程序中。但我可能是错的,请纠正我。

到目前为止,我所做的就是使用gcc进行链接。即使对于像交换raxrbx这样的小程序,它也会产生混乱的机器代码,我无法跟踪它,这对学习来说并不是很好。(请注意,程序正在运行。)

我不确定这是否相关,但这些是我正在使用的编译和链接命令:

# compilation
nasm -f elf64 swap.asm
# gcc
gcc -o swap swap.o
# ld, no c runtime
ld -s -o swap swap.o

提前感谢!


结论:

既然我已经得到了正确的答案,我想提出几个要点。像 Z boson 的回答那样(适用于64位系统),可以动态链接glibc库。如果您想静态链接,请查看此链接(我从Z boson的回答中重新发布)。

这里有一篇文章,是Jester发布的,介绍了Linux中程序如何启动

如果想了解gcc链接你的.o文件的过程,请尝试使用以下命令:gcc -v -o swap swap.o。注意,“v”代表“详细信息”。

此外,如果您对64位汇编感兴趣,应该阅读这篇文章

感谢您的回答和有益的见解!讲话结束。


2
简短回答:不要这样做。不幸的是,libc 不仅带有动态库,还有一堆用于初始化和关闭的静态对象。如果你真的想这么做,使用 gcc -v 查看所需部分。你可能会对这篇关于程序启动的精彩文章感兴趣。 - Jester
gcc -o swap swap.o 链接运行时库。而 ld -o swap swap.o 则不会链接运行时库。链接过程包括将运行时库的相当大部分内容复制到可执行文件中。那么问题究竟出在哪里呢? - n. m.
@Jester 我现在就去看看! - mrDudePerson
2
使用 gcc -v -o swap swap.o 命令来查看 gcc 如何调用 ld。你需要做更多或更少相同的事情,所以你可以省去麻烦直接使用gcc。 - n. m.
哦,现在我明白了!谢谢 :) - mrDudePerson
显示剩余3条评论
2个回答

7

以下是一个使用libc而不使用GCC的示例。

extern printf
extern _exit

section .data
    hello:     db 'Hello world!',10

section .text
    global _start   
_start:
    xor eax, eax
    mov edi, hello
    call printf
    mov rax, 0    
    jmp _exit

编译和链接方式如下:

nasm -f elf64 hello.asm
ld hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -m elf_x86_64

目前为止,这对我来说一直很好用,但是对于静态链接来说比较复杂


谢谢,我稍后会试一下。如果有效的话,我会选择这个作为正确答案 :) - mrDudePerson

2

如果您想调用简单的库函数,例如atoi,但仍要避免使用C运行时库,您可以这样做。(即您编写_start,而不是只编写一个在大量样板代码运行后被调用的main。)

gcc -o swap -nostartfiles swap.o

正如评论中所说,glibc 的某些部分依赖于从标准启动文件运行的构造函数/析构函数。也许这是 stdio (puts/printf/scanf/getchar) 和 maybe malloc 的情况。很多函数都是“纯”的函数,只是处理给定的输入。sprintf/sscanf 可能可以使用。
例如:
$ cat >exit64.asm  <<EOF
section .text

extern exit

global _start
_start:

    xor edi, edi
    jmp exit            ; doesn't return, so optimize like a tail-call

    ;; or make the syscall directly, if the jmp is commented
    mov eax, 231    ;  exit(0)
    syscall

;   movl eax, 1     ; 32bit call
;   int 0x80
EOF

$ yasm -felf64 exit64.asm && gcc -nostartfiles exit64.o -o exit64-dynamic
$ nm exit64-dynamic
0000000000601020 D __bss_start
0000000000600ec0 d _DYNAMIC
0000000000601020 D _edata
0000000000601020 D _end
                 U exit@@GLIBC_2.2.5
0000000000601000 d _GLOBAL_OFFSET_TABLE_
00000000004002d0 T _start
$ ltrace ./exit64-dynamic 
enable_breakpoint pid=11334, addr=0x1, symbol=(null): Input/output error
exit(0 <no return ...>
+++ exited (status 0) +++
$ strace ... # shows the usual system calls by the runtime dynamic linker

@mrDudePerson:不要忘记“接受”解决你问题的答案(点击上下投票箭头下方的复选框)。否则,该问题仍会显示为未回答。 - Peter Cordes

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