从c调用汇编函数
我试图从c中调用汇编函数,但总是出错从c调用汇编函数,c,linux,assembly,gcc,x86,C,Linux,Assembly,Gcc,X86,我试图从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
.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));
}
每当我尝试使用gcc-Wall function.c-o函数编译代码时,它都会给出“未定义的集成引用”错误
#include<(file path)/integrate.s>
#包括
顺便说一句,汇编代码在做什么并不重要,因为现在我只是想成功地从c调用函数。有人能帮我解决这个问题吗
警告:“main”的返回类型不是“int”
表示“main”的返回类型不是“int”。。。将其更改为int
,然后:
int main()
{
}
另外,要解决链接器错误,请根据需要调用GCC
gcc -o myprog main.c integrate.s
这应该行得通。我发现代码存在以下问题:
- 调用约定要求您必须保留
edi
正在使用cmp%edi,1024
作为地址,可能会出现故障。您需要1024
与立即数进行比较cmp$1024,%edi
- 您正在从每次迭代的参数中重新加载
和eax
,因此您执行的计算没有效果ecx
- 您似乎没有将任何合理的返回值放入
(它将返回传入的eax
的
值)
即使“汇编代码正在做什么并不重要”,前两点也适用。不确定您是否解决了这个问题,但下面是我如何解决这个问题的 编译时,确保添加两个文件:
$gcc main.c print\u msg.s-o main
要单独运行汇编程序文件:$as print\u msg.s-o print\u msg.o
,后跟$ld print\u msg.o-e print-o print\u msg
。请注意,如果您只想从C文件运行它,则不需要这样做
汇编程序文件:
print\u msg.s
# A program to be called from a C program
# Declaring data that doesn't change
.section .data
string: .ascii "Hello from assembler\n"
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
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
这是使用调用约定,其中函数返回值在rax
中传回,函数接收的参数在rdi
,rsi
,rdx
,rcx
,r8
,r9
中传回,然后按相反顺序将堆栈传递。(). 例如:
long add_four_nums(int first, long second, short third, unsigned fourth);
使用此原型声明的函数将在%edi
中接收第一个
,%rsi
中接收第二个
,%dx
中接收第三个
,在%ecx
中接收第四个
。它将在%rax
中返回其结果
现在我们已经编写了程序集(虽然函数主要是一个存根,用于显示如何接受参数和返回值),您可以在C文件中使用该函数,就像您当前使用的那样:
#include <stdio.h>
extern int integrate(int from,int to);
int main() {
printf("%d\n", integrate(1,10));
}
它的工作原理类似于gcc mprog main.c integrate.s-o out
。但这次它说的是分段fault:core dumped
。这与汇编函数中的错误有关?@AliU。现在仍然是。(你为什么多次发布此评论?)仍然是?你的意思是这是汇编函数的错误?(错误地删除了它,对不起。)@AliU。如果它编译并链接,但随后出现SEGFULTS,那么是的,我怀疑这是汇编函数的错误。您是否在运行可执行文件时附加了调试器?Jester的回答至少应该使您的程序不会崩溃。你也许应该记下他的答案。我正在考虑发布完整的汇编代码,但是在不知道汇编程序应该做什么的情况下,我真的只能做他的回答。来自
的第一个参数包含在%rdi-Nope中,在C中,您告诉编译器它是一个int
,因此只有EDI保证保存您的值,不一定是零或符号扩展到64位RDI。实际上,传递常量的简单调用程序会将其零扩展到RDI中,但是注释仍然是错误的,除非您将类型更改为uint64\t
或long
。当然,ESI也是如此。@PeterCordes很酷,谢谢你的反馈,如果你认为有帮助的话,我可以更新答案,剩下的答案看起来还可以。除此之外,一切看起来都是正确的;回答得很好,很好地解释了必要的拼图块以及它们是如何组合在一起的。(除了ISO C规定的main
的返回类型必须是int
,而不是void
,对于“托管”程序(即在操作系统下运行的程序,而不是独立的程序))是的,应该更新它。我决定自己做这件事,以便在评论和编辑中节省大量时间。@PeterCordes非常感谢您的时间和反馈!
long add_four_nums(int first, long second, short third, unsigned fourth);
#include <stdio.h>
extern int integrate(int from,int to);
int main() {
printf("%d\n", integrate(1,10));
}
$ gcc -o combined -Wall main.c integrate.s && ./combined