执行从x86程序集编译的程序时出现分段错误?

我是汇编语言的新手,我必须实现一个函数,在我的例子中是sin(x),可以从C源文件调用。 我必须制作两个单独的文件:* .c和* .s在ubuntu上通过gcc编译时都很好,但是当程序执行时它会给出错误“Segmentation fault”…

编译我输入:

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

当我启动程序时:

 ./sinx 

它打印:

 .......insert x: 

我把x放进去然后:

 segmentation fault 

它停止了 这是两个文件:

 /*-----------------------------------Sin[x]----------------------------------------*/ extern float Sin(float x); //extern assembly function #include  //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 } /*----------------------------------------------------------------------------------*/ 

 #---------------------------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 

那么,错误在哪里? 我怎么解决这个问题? 谢谢。

我建议创建一个非常简单的汇编语言函数,它只会返回它传递的相同参数。 这相当于C函数:

 float identity(float x) { return x; } 

完成这项工作将确保您在开始实际编写代码之前正确设置所有编译,汇编,链接,调用约定等。 一旦有效,编写一个函数将1添加到参数并返回该参数。 然后,在你练习之后开始实现你的Sin()函数。 你到目前为止所获得的是对于汇编语言新手的许多代码。

你真的希望有人为你调试这个吗?

指导步骤通过调试器中的程序集,然后提出问题。 “我的寄存器值是a,b,c ……,我已经执行了指令”。 为什么这个陷阱? 作为准备工作,您至少应该阅读intel指令集参考中的陷阱指令的文本,可在此处获得:

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

通常,ax寄存器系列(包括eax)用于保存汇编中的返回值。 您是否已检查并确认该值确实存储在那里。 您可能希望使用信号处理程序并捕获SIGSEGV并使用getpid()执行system(...) shelling到gdb并附加到进程并执行堆栈跟踪。

作为捕获SIGSEGV时信号处理程序中使用的示例函数:

 char buf [150];
 sprintf(buf,“echo where | gdb -a%d> mydump.data”,getpid());
系统(BUF);

然后你可以检查文件mydump.data并检查它到底是什么区分。

段错误是取消引用未初始化指针或不是malloc的结果。

希望这会有所帮助,最好的问候,汤姆。

这个汇编程序函数有多个bug 🙂

  1. 使用gdb显示在fimul指令上发生了segfault。
  2. 你不能像这样使用fimul和litteral操作数; 操作数应该是要乘以的32位值的地址,而不是litteral值本身。
  3. 要改变st0的符号,使用fchs肯定更容易。
  4. 即使有这些更改,您的汇编程序函数也不起作用(但至少,它不会发生段错误,并且在参数为零的情况下确实会返回正确的值!)