我正在尝试从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));
}
这是我的代码。
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函数编译我的代码时,它都会给出'未定义的集成引用'错误。我也尝试从c添加到integration.s文件的链接,比如
#include<(file path)/integrate.s>
但它也没有用。但是汇编代码的作用并不重要,现在我只是试图从c成功调用函数。任何人都可以帮我解决这个问题吗?
答案 0 :(得分:8)
我在代码中看到以下问题:
edi
cmp %edi,1024
使用1024
作为地址,可能会出错。您希望cmp $1024,%edi
与即时数字进行比较eax
和ecx
,因此您执行的计算无效eax
中添加任何合理的返回值(它将返回传入的from
的值)即使“汇编代码正在做什么并不重要”,前两点也适用。
答案 1 :(得分:5)
警告:'main'的返回类型不是'int'
表示'main'的返回类型不是'int'...将其更改为int
,然后:
int main()
{
}
另外,要解决链接器错误,请将GCC调用为
gcc -o myprog main.c integrate.s
这应该有用。
答案 2 :(得分:4)
不确定你是否已经解决了这个问题,但这是我如何做到的。
编译时请确保添加两个文件:$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\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
然后是C文件:main.c
extern void print(void);
int main(void)
{
print();
return 0;
}
答案 3 :(得分:3)
这里已经有一个显示如何调用 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
、rsi
中传递、rdx
、rcx
、r8
、r9
,然后以相反的顺序堆叠。 (What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64)。例如:
long add_four_nums(int first, long second, short third, unsigned fourth);
使用此原型声明的函数将在 first
中接收 %edi
,在 second
中接收 %rsi
,在 third
中接收 %dx
,以及 {{ fourth
中的 1}}。它会在 %ecx
中返回它的 result
。
既然我们已经编写了程序集(尽管该函数主要是一个存根,用于展示如何接受参数和返回值),您可以像现在一样在 C 文件中使用该函数:
%rax
可以用gcc编译链接,然后运行,如下:
#include <stdio.h>
extern int integrate(int from,int to);
int main() {
printf("%d\n", integrate(1,10));
}