如何link C语言库?

How to link C language libraries?

我有兴趣执行一个用 C 语言编写的函数:-

//filename "CLang.c"
#include<stdio.h>
void fun() {
    printf("Hello World");
}

我想通过我编写的汇编语言调用这个 fun():- (NASM 64 位)

; filename "MyASM.asm"
section .data

section .bss

section .text
global _start
_start:
    call fun
    mov rax,60  ; exit
    mov rdi,1
    syscall

我已经使用这些命令 nasm -f elf64 MyAsm.asmgcc -c CLang.c 创建了目标文件。 当我将这两个文件与 gcc gcc MyASM.o CLang.o 合并时,出现错误

MyASM.o: In function `_start':
MyASM.asm:(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

我不明白为什么说是_start的多重定义我只写了一个_start ???
我不知道如何使用 MyASM.o 仅附加 gcc 库 ???

您遇到的错误是因为您正在定义 _start 并且因为您正在使用 C 库(使用 GCC)进行编译和 linking . C 库定义了一个 _start 标签来初始化 C run-time。这两个 _start 标签是 link 人抱怨 _start 被重新定义的原因。库中的 C 启动代码负责在正确初始化所有内容后将控制权转移到 main

如果您直接或间接使用 C 库 (GLIBC) 函数,您需要确保 C 库已正确初始化通过 linking 在它的库和它的 run-time 环境中。默认情况下,这是 GCC 为您做的事情(它可以被覆盖)。

您可以将 main 定义为这样的汇编语言函数:

extern fun
section .text
global main
main:
    push rbp           ; Pushing a 64-bit register aligns stack back on 16-byte 
                       ; boundary so the call to `fun` has proper 16-byte
                       ; alignment per the AMD64(X86-64) System V ABI.
    call fun
    xor eax, eax       ; RAX=0 (main's return value)
    pop rbp            ; Restore the stack
    ret                ; Return back to C startup code which will exit for us.

您应该能够使用现有命令 assemble 与 NASM、GCC 编译和 GCC link。

您可能会找到一些关于 _start/mainC 运行时的一些额外信息,这些运行时有点相关 and information on the -nostartfiles option in the answers to this other question

在这个 Whosebug 的答案中有更多关于堆栈对齐要求的信息

一般来说,库是从许多库源文件创建的,并且要么构建为归档文件 (libmine.a),静态 linked 到使用它们的可执行文件中,要么构建为共享对象动态 link 编辑到使用它们的可执行文件中的文件 (libmine.so)。要在这些类型的库中 link,请使用 gcc 命令行选项 -L 作为库文件的路径,并使用 -l 在库(.so 或 .a)中 link:

-L{path to file containing library} -l${library name}

例如,如果我在 /home/newhall/lib/ 中有一个名为 libmine.so 的库,那么我将执行以下操作以将其 link 放入我的程序中:

$ gcc -o myprog myprog.c  -L/home/newhall/lib -lmine

您可能还需要指定并包含路径,以便编译器可以找到库头文件:-I /home/newhall/include 如果您创建自己的共享目标文件并且不将它们安装在 /usr/lib 中,那么您需要设置您的 LD_LIBRARY_PATH 环境变量,以便 运行 时间 link 用户可以找到它们并在 运行 时间加载它们。例如,如果我将我的 .so 文件放在我的主目录中名为 lib 的目录中,我会将我的 LD_LIBRARY_PATH 环境设置为以下内容:

# if running bash:
  export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH

  # if running tcsh:
  setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH