assembly - 为什么我将堆栈指针值设置为 bp 时会有 2 个字节的偏移量?
问题描述
我正在学习如何通过堆栈将参数传递给函数。我发现自己处于一种我不明白为什么的情况(一旦我pop
在堆栈上完成了各种 's 以保存数据),然后返回指令(参见调试注释):
mov ax, [bp + n]
我最终得到一个 2 字节的偏移量。我会解释的。我已经勾勒出仅在堆栈上发生的所有事情。当我接受教育时:
mov bp, sp
我复制其中包含的地址sp
(bp
在我的情况下是 00f8h)。好吧,这让我想到,从现在开始,我所指的一切,使用[bp + n]
,都是从这个地址开始的。
因此,参考我评论为 DEBUG 的区域,如果bp
= 00f8h 并且我想查看内容,我应该找到我在指令中保持不变的字节sub sp, 2
,而不是我发现自己的起始地址bp
(2 个字节高于00f8h)。
继续下一个 DEBUG 语句,我有:
mov ax, [bp + 2]
我应该找到我记住的值bp
;相反,我发现自己是调用的返回地址(比 00f8h 高 4 个字节)。
程序指令:
mov ax, [bp + 4]
我应该找到过程调用的返回地址。相反,我找到了我从cx
寄存器中保存的值。
简而言之,似乎bp
不是指 00f8h 而是指 00fah(高 2 个字节),因此帐户加起来(不幸的是,在寄存器中我发现情况并非如此)。
请不要考虑我尝试处理传递参数情况的形式;我的问题是:
为什么会有这个 2 字节的偏移量?
; Use parameterized procedures.
;
;
; To assemble an .ASM file with TASM:
; # TASM PUNTATOR.ASM /L /ZI
; # TLINK PUNTATOR.OBJ /V
dosseg
.model medium
.stack 100h
.data
num1 db 5
num2 db 3
ris db ?
.code
main proc
mov ax, dgroup ; mette il segmento dati in AX
mov ds, ax ; imposta DS in modo da puntare ai dati
xor cx, cx ; I clean up the cx registry
mov cl, num1 ; cx = 5
xor bx, bx ; I clean up the bx registry
mov bl, num2 ; bx = 3
push bx ; 2° parameter
push cx ; 1° parameter
xor ax, ax ; I prepare ax to hold the return parameter
call somma
add sp, 4 ; it's like I'm doing two pops. That is, I restore the
; stack pointer to its original value, before calling
; the two parameters above.
mov ris, al
mov ah, 02h
mov dl, cl ; print cl
add dl, '0'
int 21h
mov ah, 02h
mov dl, '+' ; print '+'
int 21h
mov ah, 02h
mov dl, bl ; print bl
add dl, '0'
int 21h
mov ah, 02h
mov dl, '=' ; print '='
int 21h
mov ah, 02h
mov dl, ris
add dl, '0'
int 21h
mov ah, 4Ch
int 21h ; Return to DOS
main endp
somma proc near
push bp ; I store the base pointer in the stack
mov bp, sp ; copy in bp the address of the stack pointer in this moment
; momento, cioè quando inizia la procedura.
sub sp, 2 ; I save 2 bytes for a local variable
push cx ; I save these two registers because I want to use them as
push dx ; registers for my local parameters, then they will be restored
; DEBUG
xor ax, ax
mov ax, [bp] ; Initial stored address of bp
mov ax, [bp + 2] ; Address of the instruction following the call
mov ax, [bp + 4] ; The value I had put from cx
mov ax, [bp + 6] ; The value I had put from bx
; END DEBUG
mov cx, [bp + 4]
mov dx, [bp + 6]
mov [bp - 2], cx
add [bp - 2], dx
mov ax, [bp - 2]
pop dx
pop cx
mov sp, bp
pop bp
ret
somma endp
end main
解决方案
我将 sp 中包含的地址复制到 bp 中(在我的例子中是 00f8h)。好吧,这让我想到,从现在开始,我使用 [bp + n] 引用的所有内容都是从这个地址开始的。
当然。
因此,参考我评论为 DEBUG 的区域,如果 bp = 00f8h 并且我想查看内容,我应该找到我用指令 sub sp, 2 保持不变的字节,而不是我找到自己的起始地址bp(比 00f8h 高 2 个字节)。
那是不对的。
我想也许你对如何工作push
和pop
工作的想法是一成不变的。 push
将减sp
2 ,然后sp
在指向 的地址存储一个字。pop
是相反的:加载然后递增。因此,如果您正在执行push
and pop
,那么sp
将始终指向位于堆栈顶部的单词,即最近推送但尚未弹出的数据。
现在您的功能以
push bp ; I store the base pointer in the stack
mov bp, sp ; copy in bp the address of the stack pointer in this moment
因此,如果bp
获取 value 00f8h
,那么这就是在sp
之后的值push
,这意味着您存储的先前值bp
是在 address 00f8h
。当你,你从地址mov ax, [bp]
加载,所以你得到旧值。 包含返回地址(位于 address ),具有第一个参数(at ),具有第二个参数(at )。ax
00f8h
bp
[bp+2]
00fah
[bp+4]
00fch
[bp+6]
00feh
您的“未更改字节”位于减去 2后sp
指向的地址,即. 如果你想访问它,你需要使用 address 。00f6h
[bp-2]
推荐阅读
- python - 练习邻接表和 BFS 的编码练习
- javascript - 是否可以在文档中获取集合以及所有其他文档数据?
- kubernetes - 为什么 pulumi kubernetes 提供商要更改服务和部署名称?
- discord.js - (Discord.js) 尝试根据频道名称获取频道ID,并在其中发布消息
- react-native - 如何在 React Native 中显示来自 Firebase Firestore 的数据
- javascript - 有没有办法在几个数组中搜索低于某个值的东西?
- python - Python中的随机函数预测
- javascript - 反应获取 div clientWidth 在组件 didUpdate 中返回 null
- ios - 视频无法在 iOS Safari 上播放
- numpy - Numba / Numpy - 理解错误信息