Assembly functions FPU with c - c

So I am writing some C with Assembly in AT&T. I've got small problem right now, because when I call first function that is f_float with float parameter, parameter is loaded from stack and returned value is proper. But with the second call f_double with double parameter, the value isn't loading from stack. I'm on linux Mint 17.1, gcc version 4.9.2(Ubuntu4.9.2-0ubuntu1~14.04). Any advices?
main.cpp
#include <stdio.h>
float f_float(float);
double f_double(double);
int main()
{
float a, f_result;
double b, d_result;
printf("\nInsert float number: ");
scanf("%f", &a);
printf("\nInsert double number: ");
scanf("%lf", &b);
f_result = f_float(a);
d_result = f_double(b);
printf("\nResult of float with f function: %f", f_result);
printf("\nResult of double with f function: %lf", d_result);
return 0;
}
functions.s
s_precision = 0x007f
d_precision = 0x027f
#(x^2)/(sqrt(x^2 +1) +1)
.globl f_float
.type f_float, #function
f_float:
pushl %ebp
movl %esp, %ebp
subl $2, %esp
finit
movl $s_precision, -2(%ebp)
fldcw -2(%ebp)
flds 8(%ebp)
fmul %st(0)
fld1
fadd %st(1), %st(0)
fsqrt
fld1
fsubr %st(1), %st(0)
movl %ebp, %esp
pop %ebp
ret
.globl f_double
.type f_double, #function
f_double:
pushl %ebp
movl %esp, %ebp
subl $2, %esp
finit
movl $d_precision, -2(%ebp)
fldcw -2(%ebp)
fldl 8(%ebp)
fmul %st(0)
fld1
fadd %st(1), %st(0)
fsqrt
fld1
fsubr %st(1), %st(0)
movl %ebp, %esp
pop %ebp
ret

Changing movl $*_precision to movw $*_precision resolved problem. That was mistake of course, but thought that it will overwrite the data left on stack later on. Anyway, problem soved. Thanks to everyone for help. – Robs

Related

stackframe dosen't get eliminated from the stack?

I wrote a single c program that prints input to std output. Then I converted it to assembly language. By the way I am using AT&T Syntax.
This is the simple C code.
#include <stdio.h>
int main()
{
int c;
while ((c = getchar ()) != EOF)
{
putchar(c);
}
return 0;
}
int c is a local variable.
Then I converted it to assembly language.
.file "question_1.c"
.text
.globl main
.type main, #function
//prolog
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp // we add 20 bytes to the stack
jmp .L2
.L3:
subl $12, %esp
pushl -12(%ebp)
call putchar
addl $16, %esp
.L2:
call getchar
movl %eax, -12(%ebp)
cmpl $-1, -12(%ebp)
jne .L3
//assumption this is the epilog
movl $0, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.9.4-2ubuntu1) 4.9.4"
.section .note.GNU-stack,"",#progbits
normally in the epilog we are supposed to addl 20 because in the prolog we subl 20.
So the is the stack frame still there?
Or am I missing out a crucial point?
I also have a question regarding the main function. Normally functions are normally "called" but where does it happen in the assembly code?
Thank you in advance.
Just after the main label, leal 4(%esp), %ecx saves four plus the stack pointer in %ecx. At the end of the routine, leal -4(%ecx), %esp writes four less than the saved value to the stack pointer. This directly restores the original value, instead of doing it by adding the amount that was subtracted.

Segmentation fault when pushing to stack in assembly

I am writing a problem to calculate smallest common multiple in assembly. GDB shows sigsegv exception at the very first line pushl %ebp. Can you tell me how to fix this?
test.c
#include <stdio.h>
extern int nww(int a, int b); // Funkcja z asm
int main()
{
int a = 10, b = 3;
int nw= nww(a,b);
printf("NWW %d i %d = %d ",a,b,nw);
return 0;
}
nww.s
.text
.global nww
.type nww, #function
nww:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl 12(%ebp), %ebx
nwd:
movl $0, %edx # miejsce na reszte
divl %ebx # podziel a przez b, reszta w d
movl %ebx, %eax
movl %edx, %ebx # przygotowanie nastepnego dzielenia
cmp $0, %edx
jnz nww
movl %eax, %edx # NWD do dx
movl 8(%ebp), %eax # nowe A i B
movl 12(%ebp), %ebx
imull %ebx, %eax
divl %edx
exit:
movl %ebp, %esp
popl %ebp
ret

assembly function with C segfault

I am trying to make assembly function that uses SSE and FPU for parallel calculations. Unfortunately I am receiving segmentation fault(core dumped) error(while debugging it doesn't show in assembly function). I also cannot step out from assembly function. Gdb shows:
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x2bffff
after ret statement.
I'm out of any ideas what may cause that type of behaviour. Maybe some of you see something I don't? Cheers.
Integrals.s
#float intgr_vert(float x)
#{
# return pow(x, 2) - 4*x + 6;
#}
s_precision = 0x007f
.bss
.lcomm holder, 4
.lcomm rect_size_vec, 16
.lcomm x_vec, 16
.lcomm result, 16
.data
four:
.float 4.0, 4.0, 4.0, 4.0
six:
.float 6.0, 6.0, 6.0, 6.0
.globl four_intgr_strips
.type four_intgr_strips, #function
four_intgr_strips:
pushl %eax
pushl %ecx
pushl %edx
pushl %ebp
movl %esp, %ebp
subl $2, %esp
movl $0, %edi
movl 20(%ebp), %eax #x position
movl 24(%ebp), %ebx #rectangle size
movw $s_precision, -2(%ebp)
finit
fldcw -2(%ebp)
pool:
movl %eax, x_vec(, %edi, 4)
movl %ebx, rect_size_vec(, %edi, 4)
movl %eax, holder
flds holder
movl %ebx, holder
flds holder #adding size of rectangle to calculate different x
fadd %st(1), %st(0)
fstps holder
movl holder, %eax
inc %edi
cmp $4, %edi
je pool_dne
jmp pool
pool_dne:
ret ###########################can't go further
.type sumAreas, #function
sumAreas:
movl $0, %edi
flds result(, %edi, 4)
inc %edi
loop:
flds result(, %edi, 4)
fadd %st(1), %st(0)
inc %edi
cmp $4, %edi
je end_loop
jmp loop
end_loop:
ret
.type calcAreas, #function
calcAreas:
movaps rect_size_vec, %xmm1
mulps %xmm1, %xmm0
movaps %xmm0, result
ret
.type calcVertical, #function
calcVertical:
movaps x_vec, %xmm0
mulps %xmm0, %xmm0
movaps x_vec, %xmm1
movups four, %xmm2
mulps %xmm1, %xmm2
subps %xmm2, %xmm0
movups six, %xmm1
addps %xmm1, %xmm0
ret
main.c
#include <stdio.h>
#include <math.h>
// x^2 - 4x + 6 integral
float four_intgr_strips(float, float);
float calc_intgr_in_as(int a, int n, float rect_size)
{
float sum = 0;
float four_rect_area;
float last_rect_l_corner = a;
for(int i = 0; i != n/4; i++)
{
four_rect_area = four_intgr_strips(last_rect_l_corner, rect_size);
sum = sum + four_rect_area;
last_rect_l_corner = last_rect_l_corner + 4*rect_size;
}
return sum;
}
int main()
{
int a, b, n;
float rect_size;
float sum;
printf("\nType integral lower bound:");
scanf("%d", &a);
printf("\nType integral upper bound:");
scanf("%d", &b);
do
{
printf("\nType rectangles number(must be multiple of 4):");
scanf("%d", &n);
}
while(n % 4 != 0);
rect_size = (float)(b - a)/n;
sum = calc_intgr_in_as(a, n, rect_size);
printf("\nArea under function is: %f with SSE", sum);
}
You have forgotten to cleanup the stack.
In the prologue you have:
pushl %eax
pushl %ecx
pushl %edx
pushl %ebp
movl %esp, %ebp
You obviously need to undo that before you ret, such as:
movl %ebp, %esp
popl %ebp
popl %edx
popl %ecx
popl %eax
ret
PS: I have already told you that unaligning the stack is a bad idea, sooner or later that will bite you. Also, next time you ask a question, mention what input you used and what output you expect.

assembly: how to extend a float to a double for sin function usage

The C version functions:
float foo1 (float a, float b)
{
return sin(a) + b;
}
double sin(double x);
double cos(double x);
cos is for a later function.
The task is to translate foo1 to assembly, but as you can see a is a float and sin expects a double parameter. Have been translating C to assembly codes for weeks now, but honestly, have no idea of how to do in this point here.
gcc is your friend - compiling with gcc -S suggests that you might want to use cvtss2sd for float to double conversion and cvtsd2ss for converting the double result back to float:
_foo1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movss 8(%ebp), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, (%esp)
calll _sin
fstpl -16(%ebp)
movss 12(%ebp), %xmm0
cvtss2sd %xmm0, %xmm0
addsd -16(%ebp), %xmm0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, -4(%ebp)
flds -4(%ebp)
addl $24, %esp
popl %ebp
ret
EDIT: this appears to be some kind of homework assignment with arbitrary constraints. If you need to avoid SSE instructions then just add -mno-sse to the command line (gcc -mno-sse ...) and you get:
_foo1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
flds 8(%ebp)
fstpl (%esp)
calll _sin
fadds 12(%ebp)
fstps -4(%ebp)
flds -4(%ebp)
addl $24, %esp
popl %ebp
ret
EDIT 2: for more compact code you can omit the stack frame (gcc -fomit-frame-pointer ...) - note however that you will lose some functionality when it comes to debugging or profiling:
_foo1:
subl $12, %esp
flds 16(%esp)
fstpl (%esp)
calll _sin
fadds 20(%esp)
fstps 8(%esp)
flds 8(%esp)
addl $12, %esp
ret

Rewriting function with fopen and fscanf from C to assembly

I wrote function in C that does work fine for me, but I need to write the same function in assembly. I generated assembly code of this function using `gcc -S rrd.c and I need some help in implementing it in asm. I'm using Linux, x86 assembly.
My C function:
double rrd (double a)
{
FILE *f=fopen("inital.txt","r");
if(f==NULL)
return 1;
double first, second;
do
{
fscanf(f, "%lf", &first);
fscanf(f, "%lf", &second);
}
while(a >= first);
close(f);
return second;
}
This is what I get:
http://pastebin.com/zyEBgTEC
And this is what I have so far:
.data
mode:
.string "r"
file:
.string "inital.txt"
format:
.string "%lf"
value:
.space 8
first:
.space 8
second:
.space 8
pointer:
.space 8
.text
.global re
re:
pushl %ebp
movl %esp, %ebp
fldl 8(%ebp)
fstpl value
pushl $mode
pushl $file
call fopen
movl %eax, pointer
cmpl $0, pointer
jne loop
jmp end
loop:
leal 16(%esp), %edx
pushl %edx
pushl $format
pushl pointer
call __isoc99_fscanf
leal 24(%esp), %edx
pushl %edx
pushl $format
pushl pointer
call __isoc99_fscanf
fldl 16(%esp)
fldl 32(%esp)
pushl pointer
call close
end:
leave
ret
Result after fldl instructions:
st0 -2.3534389814351579410727679528547297e-185 (raw 0xbd99ccccd5ffff9ac000)
st1 -1.9968719781118224876337308160145767 (raw 0xbfffff99804025016800)
My problem is that I don't exactly know where are the results of fscanf instructions and I don't know why there are those leal instructions.
Could anyone help me to rewrite this function?
So it should look like this:
wiecej:
leal pierwsza, %edx
pushl %edx
pushl $format
pushl wskaznik
call __isoc99_fscanf
leal druga, %edx
pushl %edx
pushl $format
pushl wskaznik
call __isoc99_fscanf
fldl pierwsza
fldl b
fucomip %st(1), %st
fstp %st(0)
setae %al
testb %al, %al
jne wiecej
fldl druga

Resources