英语这不是我的第一语言,所以如果我拼错了一些话对不起 . 我在堆栈方面遇到了一些麻烦,我将放在这里的所有代码都能完美运行 .
这个代码例如它很容易,我理解它的堆栈 .
.globl f
f:
push %ebx
movl 8(%esp), %eax
movl 12(%esp), %ebx
addl %ebx, %eax
ret
堆
-------
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);
}
这就是我所做的堆栈
堆
--------
8(%esp) --> x parameter of function f
--------
4(%esp) --> z parameter of function g
--------
(%esp) --> y parameter of funcion g
--------
所以现在的问题是%ebx在哪里,现在退回到这个堆栈?
1 回答
第一个代码将返回旧的
ebx
值(可能不是有效地址),而不是原始返回地址,它在ret
之前缺少pop ebx
.在第二次调用
ss:esp
指令之前ss:esp
地址的内存包含:你的"esp+x"符号不起作用,因为esp确实动态改变,所以如果你想描述那样的堆栈,你必须说明你在使用的代码中的哪个位置(esp的值) . IE浏览器 . 在
f
的条目mov eax,[esp+4]
将加载"x",但是在push ebx
之后只有一条指令同样的事情是通过mov eax,[esp+8]
实现的(英特尔语法,自己转换为"machine" gas / at&t语法,我是人类) .但即使这样,如果你将它描述为内存值,它会随着每个
push
动态地改变或写入内存,所以你仍然必须指定你在描述堆栈的执行点(就像我在call a
之前所做的那样,因为在call a
之后,在该值1
之前写入了指令addl %ebx, %eax
的地址,并且a
处的代码没有显示出来 .无论如何旧的
ebx
和返回地址始终在同一个地方的内存中(除非a
覆盖它们),它's not the content that moves. It'是由push/pop/add/sub
调整的指针esp
. (即使在你自己的堆栈之后,内存内容也将保留一段未定义的时间,因此这些值可能会保留在那里,直到你用下一个push
或call
或其他方式覆盖它们) .最后,只需编译这些东西,然后在调试器中运行它们,在开始时将内存视图放到
ss:esp-32
,并观察如何通过call
或push
等指令写入内存,以及esp
如何更改为指向"top of stack" . 调试器中的"watch it"通常比阅读文本更容易 .