如何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.asm
和 gcc -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
/main
和 C 运行时的一些额外信息,这些运行时有点相关 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
我有兴趣执行一个用 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.asm
和 gcc -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
/main
和 C 运行时的一些额外信息,这些运行时有点相关 -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