简体   繁体   English

将值从C程序传递到汇编语言

[英]Pass values from C program to Assembly language

I would like to pass values from C program to Assembly using the linked assembly method instead of inline assembly method in C. Below is the Assembly program(GCD) which is am working on. 我想使用链接汇编方法而不是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

And this is the C program from with I am trying to pass the values to assembly program 这是我正在尝试将值传递给汇编程序的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;
}

When I compile using the below method and run it. 当我使用下面的方法编译并运行它。 I get either error Floating point exception or an empty prompt waiting for input 我得到错误Floating point exception或等待输入的空提示

$ nasm -felf64 gcdasm.nasm -o gcdasm.o
$ gcc gcdasm.o gcd.c -o gcd
$ ./gcd 
Floating point exception
$ ./gcd 

I am unable to figure out the error. 我无法弄清楚错误。 Kindly help me out. 请帮助我。 Thank you. 谢谢。

Passing arguments to gcdasm() 将参数传递给gcdasm()

The two int arguments are passed through registers, not the stack. 两个int参数通过寄存器传递,而不是堆栈。 The first and second arguments are passed in the lower-half of rdi and rsi (ie: edi and esi ), respectively. 第一个和第二个参数分别在rdirsi (即: ediesi )的下半部分传递。 So, by sign extending edi and esi into rax and rbx respectively, you load the passed arguments into those registers: 因此,通过将ediesi分别扩展到raxrbx ,可以将传递的参数加载到这些寄存器中:

movsx rax, edi  ;load rax with x
movsx rbx, esi  ;load rbx with y

However, note that rbx is not a scratch register , therefore the callee needs to save it before modifying it and then restore it back before leaving the gcdasm function. 但是,请注意rbx不是临时寄存器 ,因此被调用者需要在修改它之前保存它,然后在离开gcdasm函数之前将其gcdasm

You can simply replace rbx by rcx (which isn't a callee-saved register) everywhere in your code. 你可以简单地用rbxrcx (它不是被调用者保存的寄存器)替换rbx You don't need rbp at all, so you can remove all the instructions where rbp appears. 您根本不需要rbp ,因此您可以删除rbp出现的所有指令。


Other problems 其他问题

  • There is also a problem with the logic of the program with: 该程序的逻辑也存在问题:

     mov rax, rdx ;reminder rdx as next dividend 

    Instead of this, the divisor ( rcx ) should become the dividend ( rax ) and the remainder ( rdx ) should become the divisor ( rcx ), that is: rcx除数rcx )应该成为被除数rax ), 余数rdx )应该成为除数rcx ),即:

     mov rax, rcx mov rcx, rdx 
  • When dividing signed values, you have to use the idiv instruction, not div . 划分有符号值时,必须使用idiv指令,而不是div


Improvement 起色

There are also some reasons regarding performance and code size to use test rdx, rdx instead of cmp rdx, 0 for comparing rdx against zero . 关于性能和代码大小,还有一些原因可以使用test rdx, rdx而不是cmp rdx, 0rdx与零进行比较


With all that above in mind: 考虑到以上所有因素:

;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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM