为什么我设置栈指针值为bp时会有2个字节的偏移量?
Why is there a 2 byte offset when I set the stack pointer value to bp?
我正在学习如何通过堆栈将参数传递给函数。我发现自己处于一种我不明白为什么的情况(一旦我在堆栈上完成了各种 pop
以保存数据),按照指令倒退(参见 DEBUG 注释):
mov ax, [bp + n]
我得到了一个 2 字节的偏移量。
我会解释。
我已经勾勒出所有发生在堆栈上的事情。当我接受教育时:
mov bp, sp
我将sp
中包含的地址复制到bp
中(在我的例子中是00f8h)。好吧,这让我想到,从现在开始,我使用 [bp + n]
引用的所有内容都从这个地址开始。
所以,参考我注释为DEBUG的区域,如果bp
= 00f8h并且我想查看内容,我应该找到我用指令sub sp, 2
保持不变的字节,相反,我发现自己的起始地址具有 bp
(比 00f8h 高 2 个字节)。
继续下一个 DEBUG 语句,我有:
mov ax, [bp + 2]
我应该找到我记忆中的值bp
;相反,我发现自己是调用的 return 地址(比 00f8h 高 4 个字节)。
程序指令:
mov ax, [bp + 4]
我应该找到过程调用的 return 地址。相反,我找到了我从 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
I copy the address contained in sp in bp (which in my case is 00f8h). Well, it makes me think now that everything I refer to from now on, using [bp + n], starts from this address.
当然可以。
So, referring to the area that I commented as DEBUG, if bp = 00f8h and I want to view the content, I should find the byte that I left unchanged with the instruction sub sp, 2, instead I find myself the starting address that had bp (2 bytes higher than 00f8h).
不对。
我想您可能对 push
和 pop
的工作方式有不同的看法。 push
会将 sp
减 2 ,然后 在 sp
指向的地址处存储一个字。 pop
是相反的:加载然后递增。因此,如果您正在执行 push
和 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
获得值 00f8h
,那么这就是 sp
中 push
之后的值,这意味着您存储的先前值bp
位于地址 00f8h
。当你 mov ax, [bp]
时,你从地址 00f8h
加载 ax
,所以你得到旧的 bp
值。 [bp+2]
包含return地址(位于地址00fah
),[bp+4]
有第一个参数(在00fch
),[bp+6]
有第二个参数(在 00feh
)。
你的“不变字节”在sp
指向的地址你减去2后,即00f6h
。如果你想访问它,你需要使用地址 [bp-2]
.
我正在学习如何通过堆栈将参数传递给函数。我发现自己处于一种我不明白为什么的情况(一旦我在堆栈上完成了各种 pop
以保存数据),按照指令倒退(参见 DEBUG 注释):
mov ax, [bp + n]
我得到了一个 2 字节的偏移量。
我会解释。
我已经勾勒出所有发生在堆栈上的事情。当我接受教育时:
mov bp, sp
我将sp
中包含的地址复制到bp
中(在我的例子中是00f8h)。好吧,这让我想到,从现在开始,我使用 [bp + n]
引用的所有内容都从这个地址开始。
所以,参考我注释为DEBUG的区域,如果bp
= 00f8h并且我想查看内容,我应该找到我用指令sub sp, 2
保持不变的字节,相反,我发现自己的起始地址具有 bp
(比 00f8h 高 2 个字节)。
继续下一个 DEBUG 语句,我有:
mov ax, [bp + 2]
我应该找到我记忆中的值bp
;相反,我发现自己是调用的 return 地址(比 00f8h 高 4 个字节)。
程序指令:
mov ax, [bp + 4]
我应该找到过程调用的 return 地址。相反,我找到了我从 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
I copy the address contained in sp in bp (which in my case is 00f8h). Well, it makes me think now that everything I refer to from now on, using [bp + n], starts from this address.
当然可以。
So, referring to the area that I commented as DEBUG, if bp = 00f8h and I want to view the content, I should find the byte that I left unchanged with the instruction sub sp, 2, instead I find myself the starting address that had bp (2 bytes higher than 00f8h).
不对。
我想您可能对 push
和 pop
的工作方式有不同的看法。 push
会将 sp
减 2 ,然后 在 sp
指向的地址处存储一个字。 pop
是相反的:加载然后递增。因此,如果您正在执行 push
和 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
获得值 00f8h
,那么这就是 sp
中 push
之后的值,这意味着您存储的先前值bp
位于地址 00f8h
。当你 mov ax, [bp]
时,你从地址 00f8h
加载 ax
,所以你得到旧的 bp
值。 [bp+2]
包含return地址(位于地址00fah
),[bp+4]
有第一个参数(在00fch
),[bp+6]
有第二个参数(在 00feh
)。
你的“不变字节”在sp
指向的地址你减去2后,即00f6h
。如果你想访问它,你需要使用地址 [bp-2]
.