我学习汇编程序(FASM)并且我遇到了奇怪的问题,每当我想调用gtk_main_quit()时,它总是以"分段错误"结束。
为什么调用gtk_main_quit会导致分段错误?
format ELF
extrn gtk_init
extrn gtk_main
extrn gtk_main_quit
extrn gtk_window_new
extrn gtk_widget_show
extrn g_signal_connect_data
public main
on_window_close:
call gtk_main_quit ; <- segmentation fault
ret
main:
push 0
push 0
call gtk_init
add esp, 8
push 0
call gtk_window_new
add esp, 4
mov [window_handle], eax
push 0
push 0
push 0
push on_window_close
push on_close_signal
push [window_handle]
call g_signal_connect_data
add esp, 24
push [window_handle]
call gtk_widget_show
add esp, 8
call gtk_main
window_handle dd 0
on_close_signal db 'destroy', 0
all:
~/apps/fasm/fasm ./test.asm
gcc -o test test.o `pkg-config --cflags --libs gtk+-3.0`
答案 0 :(得分:4)
进行函数调用时,请务必确保在调用后正确恢复堆栈。您的代码执行此操作:
push [window_handle]
call gtk_widget_show
add esp, 8
您将一个 DWORD 作为参数正确地推送到堆栈上,但在致电gtk_widget_show
后,您将 ESP 添加8。由于您只在堆栈上推送了4个字节,因此无法正确恢复 ESP 。副作用是函数main
的返回地址现在将位于错误的位置,这可能会在main
函数返回时产生分段错误。代码应该是:
push [window_handle]
call gtk_widget_show
add esp, 4
这引出了第二个问题。你的代码:
call gtk_main
window_handle dd 0
on_close_signal db 'destroy', 0
在gtk_main
返回后,它将开始执行后面出现在内存中的任何指令。在这种情况下,它恰好是一些变量和内存中的其他任何变量。由于 C 运行时调用函数main
与任何其他函数一样,您应该使用ret
返回 C 运行时并让它关闭你的程序干净利落。
代码如下:
call gtk_main
ret
window_handle dd 0
on_close_signal db 'destroy', 0
答案 1 :(得分:1)
对gtk_main_quit
的调用导致gtk_main
返回,在执行窗口句柄的调用之后继续执行,并且可能是文本&#34; destroy&#34;。很难准确预测会发生什么。
在ret
之后添加call gtk_main
。