我想是否可以这样理解: bp 也是一个通用寄存器, 可以进行和其它诸如 ax, bx... 一样的数据操作, 但当它被用作寄存器间接寻址时, 确缺省的段是 ss, 这和其它寄存器(bx,si,di)都不相同, 那些缺省的均为 ds, 所以在进入子程时常用这样的代码:
push bp
mov bp, sp
sub sp, xx
...
这样, 在子程中就可以通过 [bp+??] 来对堆栈式参数进行访问, 通过 [bp-??] 来对子程的局部变量进行访问, 而不需要另加 ss: 的段前缀. 相对应的子程的结束处常见为:
mov sp, bp
pop bp
ret...
当然, 这只是一种子程对堆栈式参数和其局部变量访问的比较通行的做法, 你完全可以不这么做. 我自己在查看一些程序的过程中就发现过也有不少的程序的子程用就没有通过 bp/ebp 来访问子程的参数和其局部变量, 而是直接使用的是 sp/esp. 由于在子程中的不同地方, 堆栈的可能深度不同, 所以对同样内容的访问, 可能会使用到不同的偏址. 这样的程序读起来比采用 bp/ebp 方式的来就费劲多了.
至于设计 cpu 硬件时, 为什么将 [bp] 的缺省段设定为 ss, 应该也是基于上面这个功能实现的方便上的考虑吧.
--------------------------------------------
从使用上来说,SP 总是应该指向栈顶,而 BP 可以根据自己的需要而指向堆栈的任何一个位置。
在使用 PUSH、POP 指令时,SP 是随之变化的,而 BP 不变。这就给我们在访问堆栈中的数据时,有一个相对固定的基地址。
当然,如果你整个程序段都是自己写的,而你又不必使用 BP 来访问堆栈中的数据时,那么你可以不需关心 BP 的保存值,在你的寄存器不够用的时候,你可以用它来保存一些其它的经常使用的数据,这样可以加快程序执行速度。当然,这种做法是不值得提倡的。
--------------------------------------------
不是 SP 不能变,正常使用中 SP 指向栈顶。为了避免不必要的麻烦,我认为 SP 最好一直指向栈顶,不然在调试的时候很难发现问题所在。
BP 即基址指针寄存器。
一般说来,在过程调用中,参数可以通过堆栈传送,SP 指向栈顶,我们可以通过参数入栈的先后及数据所占用的字节数,得出所需数据相对于 SP 的偏移量,访问这些数据的时候,我们可以用 SP+偏移量 去访问,另外,我们可以将 BP 指向参数,通过 BP 去访问,这样可以避免在进行堆栈操作时,因 SP 变化而影响对过程调用的参数的访问。
---------------------------------------------
个人的理解,不知道对不对。
在16位汇编代码中,sp不能进行数字操作,比如
mov (%sp + 1), %ax (at&t语法,linux Rh 7.3, gas 2.96)
不允许,所以必须用bp来代替sp,为什么要用bp,因为ss和bp一起结合,省去了段地址的设置。
在32位中,sp没有了操作限制,所以用bp反而费事。