我想使用链接的汇编方法而不是C中的内联汇编方法将值从C程序传递到汇编程序.
以下是正在进行的大会计划(GCD).
;gcdasm.nasm
bits 64
section .text
global gcdasm
gcdasm:
push rbp
mov rbp, rsp
mov rax, [rbp+4] ;load rax with x
mov rbx, [rbp+8] ;load rbx with y
top:
cmp rax, rbx ;x(rax) has to be larger than y(rbx)
je exit ;if x=y then exit and return value y
jb xchange ;if x<y then swap x and y
modulo:
cqo ;RDX:RAX sign extend
div rbx ;div rdx:rax with rbx
cmp rdx, 0 ;check remider if its 0
je exit ;if reminder is 0 then exit return return y
mov rax, rdx ;reminder rdx as next dividend
jmp modulo ;loop
xchange:
xchg rax, rbx ;swap x and y
jmp modulo
exit:
mov rax, rbx ;Return c program with the divisor y
mov rsp, rbp
pop rbp
ret
这是我正在尝试将值传递给汇编程序的C程序
//gcd.c
#include<stdio.h>
extern int gcdasm(int x, int y);
int main(void){
int x=0;
int y=0;
int result=0;
x = 46;
y = 90;
printf("%d and %d have a gcd of %d\n", x,y,gcdasm(x,y));
x = 55;
y = 66;
printf("%d and %d have a gcd of %d\n", x,y,gcdasm(x,y));
return 0;
}
当我使用下面的方法编译并运行它.我得到错误浮点异常或等待输入的空提示
$nasm -felf64 gcdasm.nasm -o gcdasm.o
$gcc gcdasm.o gcd.c -o gcd
$./gcd
Floating point exception
$./gcd
我无法弄清楚错误.请帮助我.
谢谢.
解决方法:
将参数传递给gcdasm()
两个int参数通过寄存器传递,而不是堆栈.第一个和第二个参数分别在rdi和rsi的下半部分(即:edi和esi)传递.因此,通过将edi和esi分别扩展到rax和rbx的符号,可以将传递的参数加载到这些寄存器中:
movsx rax, edi ;load rax with x
movsx rbx, esi ;load rbx with y
但是,请注意rbx不是临时寄存器,因此被调用者需要在修改它之前保存它,然后在离开gcdasm函数之前将其恢复.
你可以简单地用代码中的rcx(它不是被调用者保存的寄存器)替换rbx.您根本不需要rbp,因此您可以删除rbp出现的所有指令.
其他问题
>该程序的逻辑也存在问题:
mov rax, rdx ;reminder rdx as next dividend
除此之外,除数(rcx)应该成为被除数(rax),余数(rdx)应该成为除数(rcx),即:
mov rax, rcx
mov rcx, rdx
>划分有符号值时,必须使用idiv指令,而不是div.
起色
关于性能和代码大小,还有一些原因可以使用test rdx,rdx代替cmp rdx,0代表comparing rdx
against zero.
考虑到以上所有因素:
;gcdasm.nasm
bits 64
section .text
global gcdasm
gcdasm:
movsx rax, edi ;load rax with x
movsx rcx, esi ;load rcx with y
top:
cmp rax, rcx ;x(rax) has to be larger than y(rcx)
je exit ;if x=y then exit and return value y
jb xchange ;if x<y then swap x and y
modulo:
cqo ;sign extend RDX:RAX
idiv rcx ;rdx:rax/rcx (signed values)
test rdx, rdx ;check whether remainder is zero
je exit ;if reminder is 0 then exit return y
mov rax, rcx ;divisor becomes dividend
mov rcx, rdx ;remainder becomes divisor
jmp modulo ;loop
xchange:
xchg rax, rcx ;swap x and y
jmp modulo
exit:
mov rax, rcx ;Return c program with the divisor y
ret