如何链接C语言库?

时间:2019-06-05 17:00:19

标签: c linux gcc assembly nasm

我有兴趣执行用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库?

2 个答案:

答案 0 :(得分:3)

您得到的错误是因为您正在定义_start,并且是因为您正在编译和链接 C 库(使用GCC)。 C 库定义用于初始化 C 运行时的_start标签。这两个_start标签是链接器抱怨_start重新定义的原因。库中的 C 启动代码负责在正确初始化所有内容后将控制权转移到main

如果直接或间接使用 C 库(GLIBC)函数,则需要通过链接其库和运行来确保正确地初始化 C 库时间环境。默认情况下,这是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.

您应该能够使用现有命令与NASM进行组装,与GCC进行编译以及与GCC链接。

您可能会找到有关_start / main C 运行时的一些其他信息,这些信息与here有点相关,以及关于-nostartfiles的信息其他question的答案中的选项。

此Stackoverflow question

的答案中有关于堆栈对齐要求的更多信息。

答案 1 :(得分:-1)

通常,库是从许多库源文件创建的,或者以静态链接到使用它们的可执行文件的存档文件(libmine.a)构建,也可以动态创建为共享目标文件(libmine.so)。链接到使用它们的可执行文件中。要链接这些类型的库,请使用gcc命令行选项-L表示库文件的路径,使用-l链接到库(.so或.a):

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

例如,如果我在/ home / newhall / lib /中有一个名为libmine.so的库,则可以执行以下操作将其链接到我的程序中:

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

您可能还需要指定并包含路径,以便编译器可以找到库头文件:-I / home / newhall / include 如果创建自己的共享库文件,并且未将其安装在/ usr / lib中,则需要设置LD_LIBRARY_PATH环境变量,以便运行时链接程序可以找到它们并在运行时加载它们。例如,如果将.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