views:

445

answers:

4

Hi everybody! I'm new to assembly language and I have to implement a function, in my case sin(x), that could be called from a C source file. I have to make 2 separate files: *.c and *.s When compiling through gcc on ubuntu all good, but when the program executes it gives me the error "Segmentation fault"...

To compile I type:

gcc -c -o sinc.o sinx.c -g3
gcc -c -o sins.o sinx.s -g3
gcc -o sinx sinc.o sins.o -g3

When I start the program:

./sinx

It prints:

.......insert x:

I put x in and then:

segmentation fault

and it stops. Here are the two files:

/*-----------------------------------Sin[x]----------------------------------------*/

extern float Sin(float x);                                //extern assembly function

#include <stdio.h>                                             //necessary libraries

int main()                                                          // main function
{
    float x;                                      //allocate variable 'x' as a float
    float sine;                                //allocate variable 'sine' as a float

    printf("Calculate Sin[x], with 'x' in radians\n");      //purpose of the program

    printf("Insert 'x': ");                                            //user prompt
    scanf("%f",&x);                                                //get input value

    sine=Sin(x);                                                   //calculate sin(x)

    printf("Sin[%f]=%f\n",x,sine);                                     //print sin(x)

    return 0;                                                       //successful exit
}
/*----------------------------------------------------------------------------------*/

and

#---------------------------Sin[x]-----------------------------#
.data
.text
.globl Sin             #global function visible by main function

#function sumplus
sumplus:
   pushl  %ebp
   movl   %esp,%ebp
   fld1                                             #load 1 in ST(0)
   movl   12(%ebp),%ecx                                       #ecx=i
power:
   fmul   %st(0),%st(1)                   #ST(0)=ST(0)*ST(1),ST(1)=x
   loop   power                                #at the end ST(0)=x^i
   movl   12(%ebp),%ecx                                       #ecx=i
   xorl   %edx,%edx                           #reset edx used in mul
   movl   $1,%eax                                   #set accumulator
factorial:
   mul    %ecx                                          #eax=eax*ecx
   loop   factorial                               #at the end eax=i!
   pushl  %eax
   fild   -4(%ebp)                       #ST(0)=i!,ST(1)=x^i,ST(2)=x
   popl   %eax
   fdiv   %st(1),%st(0)                  #ST(1)=ST(1)/ST(0)=(x^i)/i!
   fld    8(%ebp)                      #load partial result in ST(0)
   fadd   %st(0),%st(2)                #ST(0)=updated partial result
   fstp   8(%ebp)               #store partial result into the stack
   fcomip %st(0),%st(0)                                      #pop i!
   fcomip %st(0),%st(0)                          #pop x^i/i!,ST(0)=x
   leave
   ret

#function summinus
summinus:
   pushl  %ebp
   movl   %esp,%ebp
   fld1                                             #load 1 in ST(0)
   movl   12(%ebp),%ecx                                       #ecx=i
power2:
   fmul   %st(0),%st(1)                   #ST(0)=ST(0)*ST(1),ST(1)=x
   loop   power2                               #at the end ST(0)=x^i
   movl   12(%ebp),%ecx                                       #ecx=i
   xorl   %edx,%edx                           #reset edx used in mul
   movl   $1,%eax                                   #set accumulator
factorial2:
   mul    %ecx                                          #eax=eax*ecx
   loop   factorial2                              #at the end eax=i!
   pushl  %eax
   fild   -4(%ebp)                       #ST(0)=i!,ST(1)=x^i,ST(2)=x
   popl   %eax
   fdiv   %st(1),%st(0)                  #ST(1)=ST(1)/ST(0)=(x^i)/i!
   fld    8(%ebp)                      #load partial result in ST(0)
   fsub   %st(0),%st(2)                #ST(0)=updated partial result
   fstp   8(%ebp)               #store partial result into the stack
   fcomip %st(0),%st(0)                                      #pop i!
   fcomip %st(0),%st(0)                          #pop x^i/i!,ST(0)=x
   leave
   ret

#function develop
develop:
   pushl %ebp
   movl  %esp,%ebp
   sub   $8,%esp                #allocate room for local variables
   movl  $9,-4(%ebp)       #store development-order,only odd values
   fldz                                          #load 0.0 in ST(0)
   fstp  -8(%ebp)           #store ST(0) and pop to collect results
Cycle:
   movl   -4(%ebp),%eax                    #eax=i,development-order
   xorl   %edx,%edx                       #reset edx because of div
   sub    $1,%eax                                              #i-1
   movl   $2,%ecx                                          #divisor
   div    %ecx                                   #eax=(i-1)/2,edx=0
   div    %ecx           #eax=((i-1)/2)/2,remainder edx=0 or edx!=0
   movl   %edx,%ecx                                  #ecx=remainder
   jecxz  Sumplus                                 #n even,(-1)^n=+1
Summinus:
   call   summinus                                 #n odd,(-1)^n=-1
   jmp    Restore                        #if sum- occured skip sum+
Sumplus:
   call   sumplus
Restore:
   movl   -4(%ebp),%ecx                            #restore counter
   sub    $2,-4(%ebp)                                 #update order
   loop   Cycle                                      #decrement ecx
   fcomip %st(0),%st(0)                                      #pop x
   fld    -8(%ebp)                       #load final result in ST(0)
   leave
   ret

#function sin
Sin:
   pushl %ebp
   movl  %esp,%ebp
   fld   8(%ebp)                   #push onto the stack 'x' value
   fldpi                           #load pi into ST(0),x in ST(1)
ControlPi:
   fcomi  %st(1)                                #compare pi and x
   jae    LoadNPi              #stop ControlPi, x is less than pi 
   fsub   %st(1),%st(0)                     #store (x-pi) in ST(1)
   jmp    ControlPi                            #return to control 
LoadNPi:            
   fimul   -1                           #(-pi) in ST(0),x in ST(1)                   
ControlPi2:
   fcomi  %st(1)                               #compare -pi and x
   jbe    PopStack        #stop ControlPi2, x is greater than -pi
   fadd   %st(1),%st(0)                     #store (x+pi) in ST(1)
   jmp    ControlPi2                           #return to control
PopStack:
   fcomip %st,%st(0)   #compare -pi to -pi then pop register stack
   call  develop                            #call develop function
   leave                                              #restore ebp
   ret                                                     #return

So,where are the errors? How can I solve this problem? Thank you.

+3  A: 

I would suggest creating a very simple assembly language function that does nothing but return the same argument it's passed. This would be equivalent to the C function:

float identity(float x) {
    return x;
}

Making this work will ensure that you have all the compiling, assembling, linking, calling conventions, etc all set up properly before you start actually writing code. Once that works, write a function to add 1 to the argument and return that. Then, start implementing your Sin() function after you've got some practice. What you've got so far is a heck of a lot of code for somebody new to assembly language.

Greg Hewgill
I've already programmed in this language but this "project" is a bit more difficult than other programs, such as factorials,partial sums,powers etc. I'm new in the sense that I'm at the first steps but actually I've already done some little steps...:)
asm
Okay, well time to bust out the debugger then! Good luck. :)
Greg Hewgill
@asm: you got good advice. There are lots of problems with the asm, you're not setting up the stack frame correctly, not initializing the local variables, not managing the FPU stack correctly. Study the code generated by C code first.
Hans Passant
+1  A: 

Generally, the ax register family (eax included) is to hold the return value in assembly. Have you checked and confirmed that the value is indeed being stored there. You might want to use a signal handler and trap the SIGSEGV and to do a system(...) shelling out to gdb using getpid() and attach to the process and do a stack trace.

As an example function used in the signal handler when SIGSEGV is trapped:

char buf[150];
sprintf(buf, "echo where | gdb -a %d > mydump.data", getpid());
system(buf);

Then you can inspect the file mydump.data and check where exactly it is seg-faulting.

Segfaults are a result of a de-referencing of a uninitialized pointer or that is not malloc'd.

Hope this helps, Best regards, Tom.

tommieb75
well,I don't know about SIGSEGV and the other things mentioned.I've read somewhere that for a float the result is returned in st(0) of the FPU...if I write factorial=fact(x), fact() has to return the integer value in %eax register, but if the value is float it couldn't be returned in a general 32-bit register....this is what I've read...
asm
@asm: See my other answer here...http://stackoverflow.com/questions/1843747/why-would-buffer-overruns-cause-segmentation-faults-when-accessing-an-integer/1843939#1843939
tommieb75
+2  A: 

Are you really expecting somebody to debug this for you as is?

Instruction step through the assembly in the debugger, and then ask the question. "My registers values are a,b,c ... , and I have executed instruction blah". Why does this trap? As preparation, you should minimally have read the text for the trapping instruction in the intel instruction set reference, available here:

http://www.intel.com/products/processor/manuals/

Peeter Joot
+4  A: 

There are more than one bug in this assembler function :)

  1. Using gdb reveals the segfault happens on the fimul instruction.
  2. You can't use fimul with a litteral operand like that; the operand should be the address of the 32-bit value you want to multiply by, not the litteral value itself.
  3. To change the sign of st0, it's definitely easier to use fchs.
  4. Even with these changes, your assembler function doesn't work (but at least, it does not segfault, and it does return the correct value in the case where the argument is zero!)
FX