英语这不是我的第一语言,所以如果我拼错了一些话对不起。我在堆栈上遇到了一些麻烦,我将放在这里的所有代码都能完美运行。
这段代码很简单,我理解它的堆栈。
.globl f f: push %ebx movl 8(%esp), %eax movl 12(%esp), %ebx addl %ebx, %eax ret
STACK
------- VAR Y --> ESP + 12 ------- VAR X --> ESP + 8 ------- RET --> RETURN ------- %EBX --> %ESP -------
但是这个代码我已经有些了
.code32 .globl f f: pushl %ebx movl 8(%esp), %ebx subl $8, %esp # Creo posto nella stack per i parametri movl $1, (%esp) movl $2, 4(%esp) call a addl %ebx, %eax addl $8, %esp #Tolgo posto nella stack popl %ebx ret
代码完美无缺,但我对此有很多疑问?现在%ebx和堆栈在哪里?
在c:
中转换的asm代码int f(int x){ return x + g(y,z); }
这就是我制作的堆栈
STACK
-------- 8(%esp) --> x parameter of function f -------- 4(%esp) --> z parameter of function g -------- (%esp) --> y parameter of funcion g --------
所以现在的问题是%ebx现在又在这个堆栈上了吗?
答案 0 :(得分:0)
第一个代码将返回旧ebx
值(可能不是有效地址),而不是原始返回地址,它会在pop ebx
之前丢失ret
。
在第二次调用中,在ss:esp
指令之前的call a
地址处的内存包含:
dword 1 +0 (current esp)
dword 2 +4
dword old_ebx_value +8
dword return_address_from_f +12
dword x +16
... older stack content ...
你的" esp + x"符号不起作用,因为esp确实动态地改变,所以如果你想描述这样的堆栈,你必须说明你在代码中的哪个位置(esp的值)。 IE浏览器。在f
的条目中,mov eax,[esp+4]
将加载" x",但只有push ebx
之后的一条指令mov eax,[esp+8]
实现相同的操作(英特尔语法,自己转换为"机器" gas / at& t语法,我是人类。
但即便如此,如果你将它描述为内存值,它会随着每个push
动态变化或写入内存,所以你仍然需要指定你在哪个执行点描述堆栈(比如我在call a
之前做了,因为在call a
之后,在该值addl %ebx, %eax
之前写入的指令1
的地址和a
处的代码是没有显示出来。
无论如何,旧ebx
和返回地址始终位于同一位置的内存中(除非a
覆盖它们),它不是移动的内容。它是由esp
调整的指针push/pop/add/sub
。 (即使在pop
之后,内存内容也将保留一段不确定的时间,如果SW中断处理程序正在使用,假设其他代码覆盖它需要多长时间是不安全的应用程序堆栈可能会随时被覆盖,但在x86 32b模式下,应用程序通常会拥有自己的堆栈,因此这些值可能会保留在那里,直到您通过下一个push
或{{1}覆盖它们或者其他一些方式)。
最后,只需要编译这些内容,然后在调试器中运行它们,将内存视图放在开头的call
,并观察如何通过ss:esp-32
或{等指令写入内存。 {1}}以及call
如何更改为指向堆栈顶部"#34;。它通常更容易观察它#34;在调试器中,而不是像我的回答一样阅读文本。