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

How to link the C Runtime Library with 'ld'?

我正在 NASM 学习汇编,以 class 我在大学里。 我想 link C 运行时库 ld,但我似乎无法包装我的绕过它。我有一台安装了 Linux Mint64 bit 机器。

我感到困惑的原因是——据我所知——不是 linkC 运行时,gcc 将你需要的东西复制到你的程序中。虽然我可能是错的,所以请不要犹豫纠正我。

到目前为止我所做的是 link 它使用 gcc。这会产生一堆我无法理解的机器代码,即使是像交换 raxrbx 这样的小程序,这对学习目的来说也不是很好。 (请注意该程序有效。)

我不确定它是否相关,但这些是我用来编译的命令 link:

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

提前致谢!


结论:

既然我对这个问题有了正确的回答,这里有几件事我想提一下。动态链接 glibc 可以像 Z boson 的回答(对于 64 位系统)那样完成。如果您想静态地进行,do follow this link(我从 Z boson 的回答中重新发布)。

这是 Jester 发表的一篇文章,关于 how programs start in linux

要查看 gcc 对 link 你的 .o-s 做了什么,试试这个命令:gcc -v -o swap swap.o。请注意 'v' 代表 'verbose'.

此外,you should read this 如果您对 64 位汇编感兴趣。

感谢的回答和有用的见解!演讲结束。

如果你想调用像atoi这样的简单库函数,但仍然避免使用C 运行时间,你可以这样做。 (即你写 _start,而不是只写一个 main 在一堆样板代码 运行 之后被调用。)

gcc -o swap -nostartfiles swap.o

正如人们在评论中所说,glibc 的某些部分依赖于标准启动文件中的 constructors/destructors 运行。 stdio (puts/printf/scanf/getchar) 和 malloc 可能就是这种情况。不过,很多函数都是 "pure" 函数,它们只处理给定的输入。 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

这是一个使用 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

像这样编译和link:

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

到目前为止,这对我来说效果很好,但 static linkage it's complicated