简体   繁体   中英

Calling Nasm function from C but return -nan

I'm learning assembly and how to call nasm function from C. So i wrote a simple code just to try it:

This is my test.c file:

#include <stdio.h>

extern int test(int c);

int main(int argc, char ** argv){
    int x = 10;
    printf("Original value: %d\nUpdated value: %d\n",x,test(x));
    return 0;

}

This is my test.nasm file:

; 32 bit

SECTION .text

global test ;unix
global _test ;windows

test:
_test:
    push ebp
    mov ebp, esp
    push ebx

    mov ebx , [ebp+8]
    mov eax, ebx
    sub eax, 2

    pop ebx
    mov esp, ebp
    pop ebp
    ret

As expected i get:

Original value: 10
Updated value: 8

But if i change test.c file as:

#include <stdio.h>

extern float test(float c);

int main(int argc, char ** argv){
    float x = 10.0;
    printf("Original value: %f\nUpdated value: %f\n",x,test(x));
    return 0;

}

The output is:

Original value: 10.000000
Updated value: -nan

Could, please, someone explain why i get this and how should i correct it? Thanks in advance.


Edit:

Thanks all for answers. I've edited the nasm file for the floating variables:

; 32 bit

SECTION .data
align 16
y:  dd  2.0 , 2.0, 2.0, 2.0

SECTION .bss
alignb 16
A:  resd    4

SECTION .text

global test ;unix
global _test ;windows

test:
_test:
    push ebp
    mov ebp,esp
    push ebx    

    movss xmm0 , [ebp+8]
    subps xmm0, [y]
    movaps [A], xmm0
    fld dword[A]        

    pop ebx
    mov esp, ebp
    pop ebp
    ret

Now it works as expected. Is that code correct?

machine code generated by C compilers generally follows a specific calling protocol , depending on the function signature. For instance, on the X86-64 platform, functions will see their parameters placed in certain registers, depending on their types and numbers: integral types (int, long, char, etc.) will be placed in generic registers ( RAX , RDX , RCX , etc), while floating point values will be passed in XMM registers. Likewise, values may be returned differently depending on the function return type.

In your case, you are targeting the IA-32 platform: the convention there is to return integral values through the x86 EAX register, and floating point values through the x87 ST0 register (parameters are still passed through the stack).

So, by changing the function signature, you are telling the compiler that test will no longer return its value the same way, and since your assembly code doesn't touch the floating point registers, you get as a result whatever was stored in there. Furthermore, subtracting the integer encoded value 2 to the 32bit floating point encoded value 10.0 (which turns out to be $41200000 ) will probably not yield what you would expect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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