我是汇编语言的新手,我必须实现一个函数,在我的例子中是sin(x),可以从C源文件调用。 我必须制作2个单独的文件:* .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 <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
}
/*----------------------------------------------------------------------------------*/
和
#---------------------------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
那么,错误在哪里?我怎么解决这个问题? 谢谢。
答案 0 :(得分:4)
我建议创建一个非常简单的汇编语言函数,它只会返回它传递的相同参数。这相当于C函数:
float identity(float x) {
return x;
}
完成这项工作将确保在开始实际编写代码之前,所有编译,汇编,链接,调用约定都已正确设置。一旦有效,编写一个函数将1添加到参数并返回该参数。然后,在练习之后开始实施Sin()
功能。你到目前为止所获得的是很多新的汇编语言代码。
答案 1 :(得分:2)
你真的希望有人为你调试这个吗?
通过调试器中的程序集指示步骤,然后提出问题。 “我的寄存器值是a,b,c ......,我已经执行了指令”。为什么这个陷阱?作为准备工作,您应该至少阅读英特尔指令集参考中的陷阱指令文本,可在此处获取:
答案 2 :(得分:1)
通常,ax寄存器系列(包括eax)用于保存汇编中的返回值。您是否已检查并确认该值确实存储在那里。您可能希望使用信号处理程序并捕获SIGSEGV并使用system(...)
对gdb进行getpid()
shelling并附加到进程并执行堆栈跟踪。
作为捕获SIGSEGV时信号处理程序中使用的示例函数:
char buf[150]; sprintf(buf, "echo where | gdb -a %d > mydump.data", getpid()); system(buf);
然后你可以检查文件mydump.data并检查它到底是什么分段。
Segfaults是取消引用未初始化指针或不是malloc的结果。
希望这有帮助, 最好的祝福, 汤姆。
答案 3 :(得分:1)
此汇编程序函数中存在多个错误:)
fimul
指令上发生了段错误。fimul
与这样的litteral操作数一起使用;操作数应该是你想要乘以的32位值的地址,而不是litteral值本身。st0
的符号,使用fchs
肯定更容易。