将值从 C 程序传递到汇编语言
Pass values from C program to Assembly language
我想使用链接汇编方法而不是 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;
}
当我使用下面的方法编译时 运行 它。我收到错误 Floating point exception
或等待输入的空提示
$ nasm -felf64 gcdasm.nasm -o gcdasm.o
$ gcc gcdasm.o gcd.c -o gcd
$ ./gcd
Floating point exception
$ ./gcd
我无法找出错误。请帮帮我。
谢谢你。
正在将参数传递给 gcdasm()
两个int
参数是通过寄存器而不是堆栈传递的。第一个和第二个参数分别在 rdi
和 rsi
的 lower-half 中传递(即:edi
和 esi
)。因此,通过将 edi
和 esi
符号分别扩展到 rax
和 rbx
,您将传递的参数加载到这些寄存器中:
movsx rax, edi ;load rax with x
movsx rbx, esi ;load rbx with y
但是,注意rbx
不是scratch register,因此callee需要在修改前保存它然后在离开 gcdasm
函数之前恢复它。
您可以简单地将代码中的任何地方的 rbx
替换为 rcx
(这不是 callee-saved 寄存器)。你根本不需要rbp
,所以你可以删除所有出现rbp
的指令。
其他问题
程序逻辑也有问题:
mov rax, rdx ;reminder rdx as next dividend
除此之外,除数 (rcx
) 应该变成 除数 (rax
) 并且余数 (rdx
) 应成为 除数 (rcx
),即:
mov rax, rcx
mov rcx, rdx
除signed值时,必须使用idiv
指令,而不是div
.
改进
对于 .
使用 test rdx, rdx
而不是 cmp rdx, 0
也有一些关于性能和代码大小的原因
考虑到以上所有内容:
;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
我想使用链接汇编方法而不是 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;
}
当我使用下面的方法编译时 运行 它。我收到错误 Floating point exception
或等待输入的空提示
$ nasm -felf64 gcdasm.nasm -o gcdasm.o
$ gcc gcdasm.o gcd.c -o gcd
$ ./gcd
Floating point exception
$ ./gcd
我无法找出错误。请帮帮我。 谢谢你。
正在将参数传递给 gcdasm()
两个int
参数是通过寄存器而不是堆栈传递的。第一个和第二个参数分别在 rdi
和 rsi
的 lower-half 中传递(即:edi
和 esi
)。因此,通过将 edi
和 esi
符号分别扩展到 rax
和 rbx
,您将传递的参数加载到这些寄存器中:
movsx rax, edi ;load rax with x
movsx rbx, esi ;load rbx with y
但是,注意rbx
不是scratch register,因此callee需要在修改前保存它然后在离开 gcdasm
函数之前恢复它。
您可以简单地将代码中的任何地方的 rbx
替换为 rcx
(这不是 callee-saved 寄存器)。你根本不需要rbp
,所以你可以删除所有出现rbp
的指令。
其他问题
程序逻辑也有问题:
mov rax, rdx ;reminder rdx as next dividend
除此之外,除数 (
rcx
) 应该变成 除数 (rax
) 并且余数 (rdx
) 应成为 除数 (rcx
),即:mov rax, rcx mov rcx, rdx
除signed值时,必须使用
idiv
指令,而不是div
.
改进
对于
test rdx, rdx
而不是 cmp rdx, 0
也有一些关于性能和代码大小的原因
考虑到以上所有内容:
;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