1

我正在尝试用 32 位 x86 AT&T 程序集编写一个简单的类似蛇的游戏,但遇到了一个奇怪的问题。我有一些 C 函数用于某些任务,例如使用 ncurses 打印到屏幕上。这个特殊的函数 ,snake_print看起来像这样:

snake_print(int x, int y, int ch){
    mvprintw(y,x,"%c",ch);
    wrefresh(screen);
}

where put_charput 是ch屏幕上的字符并refresh_scr刷新它。变量screen是全局的。

因此,要调用它,我将一些值放在堆栈上,如下所示:

subl  $12,%esp
pushl $'o'
pushl $15
pushl $15
call snake_print
addl  $12,%esp

当我从函数中查看带有 GDB 的堆栈时snake_print,它看起来应该如此。它向下移动到应该从具有正确堆栈内容的函数返回的位置,然后发生了一些事情;当 GDB 标记}snake_print正在运行的代码时,该值0x804d190被放入堆栈,同时调用snake_print(0x804d190,15,111). 再次执行的下一行代码,refresh_scr(scr)然后我得到一个分段错误。

0x804d190用 GDB 检查并看到它包含 value 0x10000f。由于在对 的新调用中snake_print,我之前的 x 值 15 被交换为 0x804d190,因此存储 x 值的内存地址似乎发生了一些事情,因为 15 = 0xf 而我们“只是一个关”,可以这么说。

我不知道为什么会发生这种情况,所以我想知道是否有人可以帮助找出问题所在?

4

1 回答 1

3

You're mixing two approaches of passing the arguments. Because both subl and the pushes change the stack, the addl is not enough to re-balance it and so your program crashes later.

You should use one or the other:

1) using pushes and restoring the stack after calls.

pushl $'o'
pushl $15
pushl $15
call snake_print
addl  $12,%esp
<...>
pushl $'p'
pushl $12
pushl $12
call snake_print
addl  $12,%esp

2) allocating stack once and using movs to set arguments.

subl  $12,%esp
<...>
movl $'o', 8(%esp)
movl $15, 4(%esp)
movl $15, 0(%esp)
call snake_print
<...>
movl $'p', 8(%esp)
movl $12, 4(%esp)
movl $12, 0(%esp)
call snake_print
<...>
addl  $12,%esp
于 2013-10-25T14:24:25.513 回答