开发者

Segmentation fault when executing program compiled from x86 assembly?

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                               开发者_如何学C               #restore ebp
   ret                                                     #return

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


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.


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/


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.


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!)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜