求助甲鱼大哥大神很棘手关于sp和bp的问题
题目是如下:当入口程序是
ebp=0019ff84
esp=0019ff78
:00401000 push ebp
:00401001 mov ebp, esp
:00401003 add esp, FFFFFFF8 esp = 0019FF70
:00401006 mov eax, dword ptr mov eax, @loc1
:00401009 mov ax, word ptr mov ax, @loc2
:0040100D mov al, byte ptr mov al, @loc3
我就是不明白ebp 跟 esp是什么关系?并且程序入口开始 ebp 也不等于 esp
程序入口时候 应该是
mov ebp, esp
push ebp
这样才对。
我就这些不懂 困扰了我 几十年。 首先,ebp(Extended Base Pointer)和esp(Stack Pointer)是x86体系结构中的寄存器。它们在汇编语言中用于管理函数调用和栈操作。
ebp通常用作帧指针,它保存了当前函数的堆栈帧的基址。堆栈帧是函数在堆栈上分配的一块内存区域,用于存储局部变量、参数以及其他与函数执行相关的信息。ebp指向堆栈帧的底部,也就是栈顶的上一个位置。
esp是栈指针,它指向当前堆栈的栈顶。当函数被调用时,esp会指向分配给该函数的新堆栈帧的顶部。在函数执行期间,esp会随着栈上的数据的推入和弹出而移动。
在你提供的代码片段中,ebp和esp的初始值分别为:
ebp = 0019ff84
esp = 0019ff78
接下来的指令序列是:
:00401000 push ebp
:00401001 mov ebp, esp
:00401003 add esp, FFFFFFF8
:00401006 mov eax, dword ptr
:00401009 mov ax, word ptr
:0040100D mov al, byte ptr
解释这些指令的作用:
1. push ebp:将当前ebp的值压入栈中,目的是为了保存上一个函数的ebp值。
2. mov ebp, esp:将esp的值赋给ebp,这样ebp现在指向了当前函数的堆栈帧的底部。
3. add esp, FFFFFFF8:将esp的值减去8个字节,即将esp向下移动8个字节。这是为了给局部变量和其他数据预留空间。
4. mov eax, dword ptr :从ebp-4的内存位置复制一个双字(4字节)到eax寄存器中。
5. mov ax, word ptr :从ebp-6的内存位置复制一个字(2字节)到ax寄存器中。
6. mov al, byte ptr :从ebp-7的内存位置复制一个字节到al寄存器中。
至于你提到的程序入口时的顺序,请注意在函数调用过程中,一般情况下参数会被压入栈中,然后调整栈指针,最后将栈指针的值赋给ebp。因此,很可能是在代码片段之前已经执行了一些与函数调用有关的指令。
希望这样解释对你有帮助!如果还有其他问题,请随时提出。
球一个最佳答案谢谢啦!这对我非常重要!{:10_254:}{:10_254:}{:10_254:}
首先,让我们先解释一下EBP和ESP在x86体系结构中的作用。
EBP(Base Pointer)和ESP(Stack Pointer)都是x86体系结构中的寄存器,他们的主要作用是用于堆栈操作。在函数调用时,EBP用于保存上一个函数的堆栈基址,而ESP则是当前堆栈的栈顶。由于堆栈是向下增长的,ESP的值总是小于EBP。
一般来说,函数开始时会将EBP的值push到堆栈上以保存它,然后将当前的ESP值复制到EBP中。这就建立了一个新的堆栈帧,可以在函数内部使用形式的寻址来访问函数的参数和局部变量。
然后,你提到的代码是常见的函数调用的prologue(序言)部分,这部分代码负责设置新的堆栈帧。代码的解释如下:
:00401000 push ebp ; 将原来的EBP值保存到堆栈
:00401001 mov ebp, esp ; 将当前的ESP值复制到EBP,建立新的堆栈帧
:00401003 add esp, FFFFFFF8 ; 分配8个字节的局部变量空间(实际上是减去8,因为堆栈是向下增长)
而在你的代码中,ebp=0019ff84和esp=0019ff78,这就意味着EBP的值大于ESP的值,也就是说堆栈已经有了一些内容。
所以,在你的代码中,虽然开始时EBP和ESP的值不同,但是通过执行push ebp和mov ebp, esp两条指令后,就建立了新的堆栈帧,同时保留了上一个函数的堆栈基址。
关于你说的“程序入口时候 应该是 mov ebp, esp push ebp 这样才对”的部分,这其实是有误的。一般来说,函数调用的序言应该是push ebp和mov ebp, esp。你可以理解为先保存旧的堆栈基址,然后建立新的堆栈帧。如果你先执行mov ebp, esp,那么原来的EBP值就丢失了,当函数返回时就无法恢复到正确的堆栈帧,会造成错误。 从新来我把完整的代码搞一下 本帖最后由 maikehong 于 2023-7-25 23:26 编辑
1 就一个子程序 程序如下
TestProc proc ;名为TestProc的子程序
local @loc1:dword, @loc2:word,@loc3:byte;一共占了 4+2+1 = 7个字节
mov eax,@loc1;对应类型进行存储,然后返回
mov ax, @loc2
mov al, @loc3
ret
TestProc endp
;====================1 以上是程序结束======2 以下是汇编情况如下============================================
:00401000 push ebp <------------3 一打开汇编停在这里入口程序中
:00401001 mov ebp, esp
:00401003 add esp, FFFFFFF8 esp = 0019FF70
:00401006 mov eax, dword ptr mov eax, @loc1
:00401009 mov ax, word ptr mov ax, @loc2
:0040100D mov al, byte ptr mov al, @loc3
============================ 4 请查看如下esp和ebp 情况 =======================================
ebp=0019ff84
esp=0019ff78
我的问题在这里有以下几点:
1 ebp和esp 的值 一开始就不相等
2 既然不相等估计前面是不是被定义的7个字节 占了 但是呢 不管 + 还是 - 也是不相等
local @loc1:dword, @loc2:word,@loc3:byte ;一共占了 4+2+1 = 7个字节
3 在汇编0基础中 甲鱼哥说ebp 是为了协助 esp 他俩并不相等他只是 ep-->寄存器 指令中没有显性的给出段地址,段地址就默认在ss中。
4 我还是搞不懂ebp本身是干嘛的 也没有被定义比如 至少前面应该
mov ebp, esp
mov push ebp
这样我好理解呀? 可是编译器就不这么做。 maikehong 发表于 2023-7-25 23:16
1 就一个子程序 程序如下
TestProc proc ;名为TestProc的子程序
ebp 算老几 凭什么 ebp 就先入栈 Mike_python小 发表于 2023-7-25 22:53
首先,ebp(Extended Base Pointer)和esp(Stack Pointer)是x86体系结构中的寄存器。它们在汇编语言中用 ...
废物一个 用来表示一处内存地址,该地址的偏移地址为 bp 寄存器中的值,段地址默认为 SS 段寄存器中的值bp指的是 内存地址sp指的是指针。我百度了一下,上面你们俩个,都是菜鸟。瞎回答 maikehong 发表于 2023-7-25 23:40
用来表示一处内存地址,该地址的偏移地址为 bp 寄存器中的值,段地址默认为 SS 段寄存器中的值bp指的是...
sp也是内存地址,我X ,到底是哪个地址。 maikehong 发表于 2023-7-25 23:42
sp也是内存地址,我X ,到底是哪个地址。
难道 ep指的是数据内存,sp指的是栈内存,但是ep就跟栈挂钩的的呀,也是指的是栈地址,难道有2个栈内存地址 1上1下。哎。ep 你把我害惨了。耽误了我几十年。 Mike_python小 发表于 2023-7-25 22:53
首先,ebp(Extended Base Pointer)和esp(Stack Pointer)是x86体系结构中的寄存器。它们在汇编语言中用 ...
下次给你一个重要的答案。我还没理解好ep 我自己先冷静冷静。做黑客不易啊。 isdkz 发表于 2023-7-25 22:53
首先,让我们先解释一下EBP和ESP在x86体系结构中的作用。
EBP(Base Pointer)和ESP(Stack Pointer)都 ...
如果 : EBP用于保存上一个函数的堆栈基址,而ESP则是当前堆栈的栈顶的
之后干嘛还要mov ebp,esp那么如果这样,对于在下一个子函数被调用时候。怎么解释呢
maikehong 发表于 2023-7-25 23:52
如果 : EBP用于保存上一个函数的堆栈基址,而ESP则是当前堆栈的栈顶的
之后干嘛还要mov ebp,esp那么 ...
ebp中保存的不是上一个函数的堆栈基址
ebp中保存的是当前函数中局部变量的基址
就是说,用ebp来访问当前函数中的局部变量
$ cat main.c
#include <stdio.h>
void func(int i) {
if(!i) return;
printf("%p\n", &i);
func(i - 1);
}
int main(void) {
func(3);
return 0;
}
$ gcc -m32 -g -Wall -o main main.c
$ ./main
0xff84bcc0
0xff84bca0
0xff84bc80
$
0000118d <func>:
#include <stdio.h>
void func(int i) {
118d: 55 pushl%ebp
118e: 89 e5 movl %esp,%ebp
1190: 53 pushl%ebx
1191: 83 ec 04 subl $0x4,%esp
1194: e8 73 00 00 00 calll120c <__x86.get_pc_thunk.ax>
1199: 05 5b 2e 00 00 addl $0x2e5b,%eax
if(!i) return;
119e: 8b 55 08 movl 0x8(%ebp),%edx
11a1: 85 d2 testl%edx,%edx
11a3: 74 2c je 11d1 <func+0x44>
printf("%p\n", &i);
11a5: 83 ec 08 subl $0x8,%esp
11a8: 8d 55 08 leal 0x8(%ebp),%edx
11ab: 52 pushl%edx
11ac: 8d 90 14 e0 ff ff leal -0x1fec(%eax),%edx
11b2: 52 pushl%edx
11b3: 89 c3 movl %eax,%ebx
11b5: e8 96 fe ff ff calll1050 <printf@plt>
11ba: 83 c4 10 addl $0x10,%esp
func(i - 1);
11bd: 8b 45 08 movl 0x8(%ebp),%eax
11c0: 83 e8 01 subl $0x1,%eax
11c3: 83 ec 0c subl $0xc,%esp
11c6: 50 pushl%eax
11c7: e8 c1 ff ff ff calll118d <func>
11cc: 83 c4 10 addl $0x10,%esp
11cf: eb 01 jmp 11d2 <func+0x45>
if(!i) return;
11d1: 90 nop
}
11d2: 8b 5d fc movl -0x4(%ebp),%ebx
11d5: c9 leavel
11d6: c3 retl
000011d7 <main>:
int main(void) {
11d7: 8d 4c 24 04 leal 0x4(%esp),%ecx
11db: 83 e4 f0 andl $0xfffffff0,%esp
11de: ff 71 fc pushl-0x4(%ecx)
11e1: 55 pushl%ebp
11e2: 89 e5 movl %esp,%ebp
11e4: 51 pushl%ecx
11e5: 83 ec 04 subl $0x4,%esp
11e8: e8 1f 00 00 00 calll120c <__x86.get_pc_thunk.ax>
11ed: 05 07 2e 00 00 addl $0x2e07,%eax
func(3);
11f2: 83 ec 0c subl $0xc,%esp
11f5: 6a 03 pushl$0x3
11f7: e8 91 ff ff ff calll118d <func>
11fc: 83 c4 10 addl $0x10,%esp
return 0;
11ff: b8 00 00 00 00 movl $0x0,%eax
}
1204: 8b 4d fc movl -0x4(%ebp),%ecx
1207: c9 leavel
1208: 8d 61 fc leal -0x4(%ecx),%esp
120b: c3 retl
在func函数中,ebp + 0x8就是局部变量 i 的地址
这个程序输出了3个局部变量 i 的地址,都不一样
118d: 55 pushl%ebp
118e: 89 e5 movl %esp,%ebp
// ...
11d5: c9 leavel
11d6: c3 retl
这4行指令保证了正常的函数调用和返回
如果不这么做,要如何才能实现这个程序的输出效果呢?
自己调试一下这个程序,看一看为什么输出的这3个局部变量 i 的地址不一样
看一看是如何通过ebp访问局部变量的
人造人 发表于 2023-7-26 00:23
在func函数中,ebp + 0x8就是局部变量 i 的地址
这个程序输出了3个局部变量 i 的地址,都不一样
...
我先分析分析你的代码 maikehong 发表于 2023-7-26 01:17
我先分析分析你的代码
你的汇编代码 入口地址不是main函数啊, maikehong 发表于 2023-7-26 01:17
我先分析分析你的代码
你这个编译器 不准确 需要在各个角度来看ebp 比如
1 在main函数中 没有调用字程序的情况下 来看ebp 和 esp
2 在main函数中调用 子程序的情况下来看ebp和sp
3 在子程序中 调用 子程序的情况下来看ebp和sp
4 看了很多关于ebp和esp 各个将的云里雾里 都有道理,
5 是不是也要在本身电脑配置的情况下来看esp和ebp 都说1 esp 永远指向 栈顶(高位),ebp 指向 栈低(低位), 也没有说清楚栈低是啥
都说2ebp是用于保存上一个函数的堆栈基址,也没有说清楚,上个函数栈基地址是啥。难道是main函数的句柄吗
都说3ebp是ss的左膀右臂,神雕侠侣杨过不就是独臂吗?
都说4ebp你算老几呀,一开局就push 凭什么你先push。 maikehong 发表于 2023-7-25 20:39
废物一个
感谢你的自我介绍
页:
[1]
2