Ali*_* U. 6 c x86 assembly inline-assembly
我试图从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
Run Code Online (Sandbox Code Playgroud)
这是我的汇编函数,名为integrate.s的文件.
#include <stdio.h>
extern int integrate(int from,int to);
void main()
{
printf("%d",integrate(1,10));
}
Run Code Online (Sandbox Code Playgroud)
继承人我的代码.
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
Run Code Online (Sandbox Code Playgroud)
每当我尝试使用gcc -Wall function.c -o函数编译我的代码时,它会给出'未定义的集成引用'错误.我也试过从c添加到integration.s文件的链接,就像
#include<(file path)/integrate.s>
Run Code Online (Sandbox Code Playgroud)
但它也没有用.比如汇编代码正在做什么并不重要,现在我只是试图从c成功调用函数.任何人都可以帮我解决这个问题吗?
sam*_*249 11
这里已经有一个答案展示了如何调用 a 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: /sf/ask/4608591151/#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
Run Code Online (Sandbox Code Playgroud)
这是使用System V调用约定,其中函数返回值被传回rax,函数接收的参数被传入rdi, rsi, rdx, rcx,r8 , r9,然后以相反的顺序传入堆栈。(i386 和 x86-64 上 UNIX 和 Linux 系统调用(和用户空间函数)的调用约定是什么)。例如:
long add_four_nums(int first, long second, short third, unsigned fourth);
Run Code Online (Sandbox Code Playgroud)
使用此原型声明的函数将接收firstin %edi, secondin %rsi, thirdin%dx和fourthin %ecx。它将返回其resultin %rax。
现在我们已经编写了程序集(尽管该函数主要是一个存根,用于显示如何接受参数并返回值),您可以像当前一样在 C 文件中使用该函数:
#include <stdio.h>
extern int integrate(int from,int to);
int main() {
printf("%d\n", integrate(1,10));
}
Run Code Online (Sandbox Code Playgroud)
它可以用 gcc 编译并链接,然后运行,如下所示:
$ gcc -o combined -Wall main.c integrate.s && ./combined
Run Code Online (Sandbox Code Playgroud)
我看到代码存在以下问题:
edicmp %edi,1024正在使用1024地址,可能会出错.您想要cmp $1024,%edi与即时数字进行比较eax,并ecx从参数每次迭代,所以你执行计算没有影响eax(它将返回from传入的值)即使"汇编代码正在做什么并不重要",前两点也适用.
小智 5
警告:'main'的返回类型不是'int'
意味着'main'的返回类型不是'int'...将其更改为int,然后:
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
另外,要解决链接器错误,请将GCC调用为
gcc -o myprog main.c integrate.s
Run Code Online (Sandbox Code Playgroud)
这应该工作.
不确定你是否已经解决了这个问题,但这是我如何做到的。
编译时确保添加两个文件: $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
Run Code Online (Sandbox Code Playgroud)
然后是C文件: main.c
extern void print(void);
int main(void)
{
print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)