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