反汇编函数调用过程变量存放有关问题
反汇编函数调用过程变量存放问题
变量存放在栈里,第一个变量放在栈低,那不是前面有寄存器入栈了吗,那变量存放进去不破坏原先入栈的数据?
------解决思路----------------------
每次压栈会有两个动作,一个是栈指针增加。一个是赋值。
栈指针增加了,就不指向原来栈底压的寄存器。就不会覆盖了。
------解决思路----------------------
------解决思路----------------------
《The Intel 64 and IA-32 Architectures Software Developer's Manual》
栈中的变量通常包括函数参数和函数里声明的临时变量。
栈中的基本变量退出其作用域时,没有谁执行一段代码去释放/销毁/析构它所占用的内存,仅仅是没人再去理会的留在当前栈顶上方的若干遗留下来可被后续压栈操作覆盖的无用数据而已。
而栈中的类变量退出其作用域时,会自动执行其析构函数,……
理解和讨论之前请先学会如何观察!
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……
对学习编程者的忠告:
多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
变量存放在栈里,第一个变量放在栈低,那不是前面有寄存器入栈了吗,那变量存放进去不破坏原先入栈的数据?
------解决思路----------------------
每次压栈会有两个动作,一个是栈指针增加。一个是赋值。
栈指针增加了,就不指向原来栈底压的寄存器。就不会覆盖了。
------解决思路----------------------
/*
The caller pushes the function's parameters on the stack, one after another, in reverse order (right to left, so that the first argument specified to the function is pushed last).
The caller then executes a CALL instruction to pass control to the callee. This CALL is either near or far depending on the memory model.
The callee receives control, and typically (although this is not actually necessary, in functions which do not need to access their parameters) starts by saving the value of SP in BP so as to be able to use BP as a base pointer to find its parameters on the stack. However, the caller was probably doing this too, so part of the calling convention states that BP must be preserved by any C function. Hence the callee, if it is going to set up BP as a frame pointer, must push the previous value first.
The callee may then access its parameters relative to BP. The word at [BP] holds the previous value of BP as it was pushed; the next word, at [BP+2], holds the offset part of the return address, pushed implicitly by CALL. In a small-model (near) function, the parameters start after that, at [BP+4]; in a large-model (far) function, the segment part of the return address lives at [BP+4], and the parameters begin at [BP+6]. The leftmost parameter of the function, since it was pushed last, is accessible at this offset from BP; the others follow, at successively greater offsets. Thus, in a function such as printf which takes a variable number of parameters, the pushing of the parameters in reverse order means that the function knows where to find its first parameter, which tells it the number and type of the remaining ones.
The callee may also wish to decrease SP further, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets from BP.
The callee, if it wishes to return a value to the caller, should leave the value in AL, AX or DX:AX depending on the size of the value. Floating-point results are sometimes (depending on the compiler) returned in ST0.
Once the callee has finished processing, it restores SP from BP if it had allocated local stack space, then pops the previous value of BP, and returns via RETN or RETF depending on memory model.
When the caller regains control from the callee, the function parameters are still on the stack, so it typically adds an immediate constant to SP to remove them (instead of executing a number of slow POP instructions). Thus, if a function is accidentally called with the wrong number of parameters due to a prototype mismatch, the stack will still be returned to a sensible state since the caller, which knows how many parameters it pushed, does the removing.
以三个参数为例子
fun(p0, p1, p2);
1.参数入栈,right->left
gcc的做法:其中p012姑且认为是立即数
movl $p2 8(%esp)
movl $p1 4(%esp)
movl $p0 (%esp)
------解决思路----------------------
_______
------解决思路----------------------
ebp->
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
<-esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
2.call fun
------解决思路----------------------
_______
------解决思路----------------------
ebp->
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
------解决思路----------------------
__ret__
------解决思路----------------------
<-esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
3.跳转到fun代码
push %ebp
movl %esp, %ebp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
------解决思路----------------------
__ret__
------解决思路----------------------
ebp->
------解决思路----------------------
__ebp__
------解决思路----------------------
<-esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
其中存储的ebp是第2步中的ebp,即之前的ebp,不是图左面的ebp
如果栈向低地址增长
那么
old ebp = [ebp]
ret = [ebp + 4]
p0 = [ebp + 8]
p1 = [ebp + 12]
p2 = [ebp + 16]
4.
decrease ESP further, so as to allocate space on the stack for local variables,
which will then be accessible at negative offsets from EBP.
subl $-24, %esp
根据具体需要分配栈空间,这里示例24/4=6个4B局部变量
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
------解决思路----------------------
__ret__
------解决思路----------------------
ebp->
------解决思路----------------------
__ebp__
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
<= esp + 12 = ebp - 12
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
<-esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
5.返回
5.1 调整栈指针
方式1:addl $24, %esp
方式2:movl %ebp, %esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
------解决思路----------------------
__ret__
------解决思路----------------------
ebp->
------解决思路----------------------
__ebp__
------解决思路----------------------
<-esp
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
5.2弹出旧frame指针=销毁当前栈帧
popl %ebp
------解决思路----------------------
_______
------解决思路----------------------
ebp->
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
------解决思路----------------------
__ret__
------解决思路----------------------
<-esp
------解决思路----------------------
__ebp__
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
5.3 返回调主
ret
------解决思路----------------------
_______
------解决思路----------------------
ebp->
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
__p2___
------解决思路----------------------
------解决思路----------------------
__p1___
------解决思路----------------------
------解决思路----------------------
__p0___
------解决思路----------------------
<-esp
------解决思路----------------------
__ret__
------解决思路----------------------
------解决思路----------------------
__ebp__
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
------解决思路----------------------
_______
------解决思路----------------------
上面说要调整esp,把参数移出掉。gcc没有做这一步。esp就保留在这里
当下面再次调用函数时,旧值就被覆盖掉。参看第一步!
5.1和5.2步,可以使用leave指令代替
*/
------解决思路----------------------
《The Intel 64 and IA-32 Architectures Software Developer's Manual》
栈中的变量通常包括函数参数和函数里声明的临时变量。
栈中的基本变量退出其作用域时,没有谁执行一段代码去释放/销毁/析构它所占用的内存,仅仅是没人再去理会的留在当前栈顶上方的若干遗留下来可被后续压栈操作覆盖的无用数据而已。
而栈中的类变量退出其作用域时,会自动执行其析构函数,……
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……
对学习编程者的忠告:
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!
VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)