在汇编代码中调用 gtk_main_quit 导致 "segmentation fault"
Call to gtk_main_quit causes "segmentation fault" in assembler code
我正在学习汇编程序 (FASM),我遇到了一个奇怪的问题,每当我想调用 gtk_main_quit() 它总是以 "segmentation fault".
结尾
为什么调用gtk_main_quit会导致段错误?
test.asm
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`
对 gtk_main_quit
的调用导致 gtk_main
到 return,在调用执行 window 句柄之后继续执行,可能还有文本 "destroy"。很难准确预测会发生什么。
在call gtk_main
之后添加ret
。
进行函数调用时,始终确保在调用后正确恢复堆栈。您的代码执行此操作:
push [window_handle]
call gtk_widget_show
add esp, 8
你将一个 DWORD 作为正确的参数压入堆栈,但在你调用 gtk_widget_show
之后你将 8 添加到 ESP。由于您只将 4 个字节压入堆栈,因此无法正确恢复 ESP。副作用是函数 main
的 return 地址现在将位于错误的位置,这可能会在您的 main
函数 return 时产生分段错误。代码应该是:
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
returns 之后它将开始执行之后出现在内存中的任何指令。在这种情况下,它恰好是一些变量和内存中的任何其他内容。由于 C 运行时调用你的函数 main
就像任何其他函数一样,你应该使用 ret
到 return 回到 C 运行时并让它干净地关闭你的程序。
代码如下所示:
call gtk_main
ret
window_handle dd 0
on_close_signal db 'destroy', 0
我正在学习汇编程序 (FASM),我遇到了一个奇怪的问题,每当我想调用 gtk_main_quit() 它总是以 "segmentation fault".
结尾为什么调用gtk_main_quit会导致段错误?
test.asm
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`
对 gtk_main_quit
的调用导致 gtk_main
到 return,在调用执行 window 句柄之后继续执行,可能还有文本 "destroy"。很难准确预测会发生什么。
在call gtk_main
之后添加ret
。
进行函数调用时,始终确保在调用后正确恢复堆栈。您的代码执行此操作:
push [window_handle]
call gtk_widget_show
add esp, 8
你将一个 DWORD 作为正确的参数压入堆栈,但在你调用 gtk_widget_show
之后你将 8 添加到 ESP。由于您只将 4 个字节压入堆栈,因此无法正确恢复 ESP。副作用是函数 main
的 return 地址现在将位于错误的位置,这可能会在您的 main
函数 return 时产生分段错误。代码应该是:
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
returns 之后它将开始执行之后出现在内存中的任何指令。在这种情况下,它恰好是一些变量和内存中的任何其他内容。由于 C 运行时调用你的函数 main
就像任何其他函数一样,你应该使用 ret
到 return 回到 C 运行时并让它干净地关闭你的程序。
代码如下所示:
call gtk_main
ret
window_handle dd 0
on_close_signal db 'destroy', 0