从 c 调用汇编函数
- 2024-10-28 08:37:00
- admin 原创
- 57
问题描述:
我正在尝试从 c 调用汇编函数,但一直出现错误。
.text
.globl integrate
.type integrate, @function
integrate:
push %ebp
mov %esp, %ebp
mov $0,%edi
start_loop:
cmp %edi,1024
je loop_exit
mov 8(%ebp),%eax
mov 12(%ebp),%ecx
sub %eax,%ecx
add %edi,%ecx
incl %edi
jmp start_loop
loop_exit:
movl %ebp, %esp
popl %ebp
ret
这是我的汇编函数,文件名为integrate.s。
#include <stdio.h>
extern int integrate(int from,int to);
void main()
{
printf("%d",integrate(1,10));
}
这是我的 C 代码。
function.c:5:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
/tmp/cciR63og.o: In function `main':
function.c:(.text+0x19): undefined reference to `integrate'
collect2: ld returned 1 exit status
每当我尝试使用 gcc -Wall function.c -o function 编译代码时,它都会给出“未定义的对 integration 的引用”错误。我还尝试从 c 添加到 integration.s 文件的链接,例如
#include<(file path)/integrate.s>
但它没有很好地工作。顺便说一下,汇编代码的作用并不重要,现在我只是想成功地从 c 调用该函数。有人能帮我解决这个问题吗?
解决方案 1:
x86-64 Linux 示例
这里已经有一个答案显示了如何调用void func(void)
,但这里有一个x86-64 Linux 示例,它接受参数并具有返回值,这正是问题中所要求的。 (该问题和其他一些答案使用的是 32 位代码,它具有不同的调用约定)。
首先,让我们简化一下组装功能:
# Need to make it global so it can be accessed in another file with extern
.globl integrate
# Cannot hurt to define it as a function type, sometimes useful for dynamic linking, see comments in: https://stackoverflow.com/questions/65837016/how-to-call-a-function-in-an-external-assembly-file#comment116408928_65837016
.type integrate, @function
integrate:
# int integrate(int from /*EDI*/, int to /*ESI*/)
# INPUT:
# the first parameter `from` is contained in %edi, the int-sized low half of %rdi
# the second parameter `to` is contained in %esi
# OUTPUT:
# return is passed in %eax;
# you can leave garbage in the high half of RAX if convenient
lea 123(%rdi, %rsi), %ecx # from + to + 123 just for example
# (main work of function done)
mov %ecx, %eax # it seems your return value is in %ecx
# but we need it in %eax for the return value to C
# or just use EAX instead of ECX in the first place to avoid this instruction
ret
这是使用System V调用约定,其中函数返回值被传回,并且函数接收的参数以相反的顺序rax
传入rdi
、、、、、,然后传入堆栈。(i386 和 x86-64 上 UNIX 和 Linux 系统调用(和用户空间函数)的调用约定是什么)。例如:rsi
`rdxrcx
r8`r9
long add_four_nums(int first, long second, short third, unsigned fourth);
使用此原型声明的函数将接收first
in %edi
、second
in %rsi
、third
in%dx
和fourth
in %ecx
。它将返回其result
in %rax
。
现在我们已经编写了汇编代码(尽管该函数主要是一个存根,用于展示如何接受参数和返回值),您可以像现在一样在 C 文件中使用该函数:
#include <stdio.h>
extern int integrate(int from,int to);
int main() {
printf("%d
", integrate(1,10));
}
它可以与 gcc 编译并链接,然后运行,如下所示:
$ gcc -o combined -Wall main.c integrate.s && ./combined
解决方案 2:
我发现代码存在以下问题:
调用约定要求你必须保留
edi
cmp %edi,1024
用作1024
地址,可能会出错。您需要cmp $1024,%edi
与立即数进行比较eax
每次迭代时,您都会重新加载ecx
参数,因此执行的计算不会产生任何效果你似乎没有输入任何合理的返回值
eax
(它将返回from
传入的值)
即使“汇编代码的作用并不重要”,前两点仍然适用。
解决方案 3:
不确定您是否已解决这个问题,但这是我解决的方法。
编译时请确保添加两个文件:$gcc main.c print_msg.s -o main
要单独运行汇编程序文件:$as print_msg.s -o print_msg.o
后跟$ld print_msg.o -e print -o print_msg
。请注意,如果您只想从 C 文件运行它,则不需要这样做。
汇编文件:print_msg.s
# A program to be called from a C program
# Declaring data that doesn't change
.section .data
string: .ascii "Hello from assembler
"
length: .quad . - string
# The actual code
.section .text
.global print
.type print, @function #<-Important
print:
mov $0x1,%rax # Move 1(write) into rax
mov $0x1,%rdi # Move 1(fd stdOut) into rdi.
mov $string,%rsi # Move the _location_ of the string into rsi
mov length,%rdx # Move the _length_ of the string into rdx
syscall # Call the kernel
mov %rax,%rdi # Move the number of bytes written to rdi
mov $0x3c,%rax # Move 60(sys_exit) into rax
syscall # Call the kernel
然后是 C 文件:main.c
extern void print(void);
int main(void)
{
print();
return 0;
}
解决方案 4:
警告:'main' 的返回类型不是 'int'
意味着'main'的返回类型不是'int'...将其更改为int
,然后:
int main()
{
}
另外,为了解决链接器错误,请按如下方式调用 GCC
gcc -o myprog main.c integrate.s
这应该可行。
解决方案 5:
第一个变化:
/* void main() */
int main(void)
main
不能为 void,必须返回一个整数(通过错误)。为了C
查看您的integrate
函数,您必须在头文件或 C 文件中指定其函数签名,然后您可以执行以下操作:
as -o integrate.o integrate.s
然后,执行以下操作:
gcc -Wall -c c_program.c
最后,执行以下操作:
gcc c_program.o integrate.o -o integrate
然后尝试:
./integrate
或者
sudo chmod u+x ./integrate && ./integrate
注意:头文件看起来应该是这样的:
/* integrate.h */
#ifndef INTEGRATE
#define INTEGRATE
return_type integrate(ARGS, ...); /*if any ARGS are passed*/
#endif
并将其放在#include "integrate.h"
C 文件的顶部。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件