Reputation: 2978
I have this example. For my task I need for using float
instead of int
:
#include <stdio.h>
extern float my_pow(float base, float exp);
int main(int argc, char const *argv[]) {
float base = 2.0, exp = 8.0;
printf("Result: %f\n", my_pow(base, exp));
return 0;
}
Build with nasm and gcc:
nasm -f macho64 calc.asm
gcc -m64 -o main main.c calc.o
As a output I get this:
Result: 2.000000
When my result should be 256.0
.
What I am doing wrong?
UPDATE: my asm code did not change
global _my_pow
section .text
_my_pow:
push rbp ; create stack frame
mov rbp, rsp
cmp edi, 0 ; Check if base is negative
mov eax, 0 ; and return 0 if so
jl end
mov eax, edi ; grab the "base" argument
mov edx, esi ; grab the "exponent" argument
multiply:
imul eax, edi ; eax * base
sub esi, 1 ; exponent - 1
cmp esi, 1 ; Loop if exponent > 1
jg multiply
end:
pop rbp ; restore the base pointer
ret ; return from procedure
Upvotes: 0
Views: 702
Reputation: 316
I'd like to expand on Peter's answer because what he's saying might not be clear to beginners.
In the first part of your code under _my_pow you get the first two arguments from edi and esi, which would be correct for most x86_64 functions. However it's different with floating point numbers. When dealing with floating point numbers the first argument is in register xmm0, and the second argument is in xmm1. A float return value is returned in xmm0.
So what Peter was saying is that the C complier will put the arguments you provide in those registers (because that's what the prototype you used + the calling convention require it to do). Since you don't operate on them in your code you just end up with your base
argument in xmm0 at the end. And that means your base
argument 2.0 gets returned to C as the return value.
Look up instructions like "movss" and "mulss" online, those are the kind of instructions you need to know to do this right. (Links to docs in the x86 tag wiki)
Upvotes: 2