Pointers 汇编语言栈和子程序

Pointers 汇编语言栈和子程序,pointers,assembly,stack,byte,Pointers,Assembly,Stack,Byte,对于堆栈指针和字节指针是如何工作的,我真的很困惑。以下是问题所引用的代码段: .data v1 db 'AB' v2 db 'CD' v3 db 'EF .code start: mov ax,@data mov ds,ax mov sp,0100h ;call the subroutine mov ax,offset v1 push ax mov ax,offset v2 push

对于堆栈指针和字节指针是如何工作的,我真的很困惑。以下是问题所引用的代码段:

    .data
v1  db  'AB'
v2  db  'CD'
v3  db  'EF

    .code
start:
     mov  ax,@data
     mov  ds,ax
     mov  sp,0100h

;call the subroutine
     mov  ax,offset v1
     push ax
     mov  ax,offset v2
     push ax
     call subr
retsub:
子程序是:

subr:
     push bp
     mov  bp,sp
     mov  si,[bp+6]
     add  si,1
     mov  dl,[si]
     mov  ah,2
     int  21h
     pop  bp
     ret
与此问题相关的三个复习问题的答案如下:
1.在子程序中的
mov bp,sp
之后,
bp
中的十六进制值为
00F8

2.子例程将单个ASCII字符写入标准输出。它写入
B

3.子程序返回主程序后,
sp
寄存器中的十六进制值位于标签
retsub
处的指令处,为
00FC

有人能带我走过这些步骤,让我更好地理解这个过程吗

我拥有的偏移数据表是:

offset  00  01  02  03  04  05
data    41  42  43  44  45  46
我在脑海中处理这个问题的方式是:

mov  sp,0100h      ;sp = 0100
mov  ax,offset v1  ;ax = 4142
push ax            ;4142 is pushed onto the stack
mov  ax,offset v2  ;ax = 4344
push ax            ;4344 is pushed onto the stack
call subr

stack
------
|4344|
------
|4142|
------
这是我所能理解的,我确信我甚至没有把这部分做对。如果可以的话,请详细说明bp和sp在每个步骤中的作用,这样我就可以跟进,并希望能将其应用到另一个复习问题上

在子程序中mov bp、sp之后,bp中十六进制值的值为00F8

是的,因为sp是用100h初始化的,所以会推送两个字大小的参数(推送ax),调用子例程,将2字节的返回地址推送到堆栈上,并执行最后一次推送bp,将sp再减少2字节。所以我们有100h-2-2-2-2=00F8h。堆栈在英特尔CPU上的内存中向下增长

在子例程返回到主程序的标签retsub处的指令后,sp寄存器中的十六进制值为00FC

这是因为子程序退出时带有一条“pop bp”指令,然后是一条ret指令,该指令从堆栈中弹出(从sp读取并增加sp)一个返回地址。所以00F8+2+2=00FC

在子程序中mov bp、sp之后,bp中十六进制值的值为00F8

是的,因为sp是用100h初始化的,所以会推送两个字大小的参数(推送ax),调用子例程,将2字节的返回地址推送到堆栈上,并执行最后一次推送bp,将sp再减少2字节。所以我们有100h-2-2-2-2=00F8h。堆栈在英特尔CPU上的内存中向下增长

在子例程返回到主程序的标签retsub处的指令后,sp寄存器中的十六进制值为00FC


这是因为子程序退出时带有一条“pop bp”指令,然后是一条ret指令,该指令从堆栈中弹出(从sp读取并增加sp)一个返回地址。因此,00F8+2+2=00FC。

每次推压都会根据推压元件的大小减小
sp
。每个pop的增量
sp
类似

所以,你从
sp
=100h开始,然后

  • push ax减去2
  • push ax减去2
  • call subr
    减去2,因为call推送返回地址,这里是16位
  • 按下bp
    减去2,得出
    sp
    =0F8h
  • 添加2个带有
    pop bp
  • 使用
    ret
    添加2,删除16位返回地址,并到达
    sp
    =0FCh

  • 每次推送都会按推送元素的大小递减
    sp
    。每个pop的增量
    sp
    类似

    所以,你从
    sp
    =100h开始,然后

  • push ax减去2
  • push ax减去2
  • call subr
    减去2,因为call推送返回地址,这里是16位
  • 按下bp
    减去2,得出
    sp
    =0F8h
  • 添加2个带有
    pop bp
  • 使用
    ret
    添加2,删除16位返回地址,并到达
    sp
    =0FCh

  • 我在任何地方都看不到
    FAR
    关键字(既不在
    call
    指令中,也不在
    ret
    指令中,也没有
    PROC
    ),因此返回地址为2字节长。其他2个字节来自推送bp。Alex,你是对的。我回答得太快,没有正确地想清楚。我已经编辑了我的答案和你的+1。谢谢,我想我理解堆栈的递增/递减。我仍然对间接寻址有点迷茫,无法完全理解代码的内容。我在任何地方都看不到
    FAR
    关键字(既不在
    call
    指令中,也不在
    ret
    指令中,也没有
    PROC
    ),因此返回地址为2字节长。其他2个字节来自推送bp。Alex,你是对的。我回答得太快,没有正确地想清楚。我已经编辑了我的答案和你的+1。谢谢,我想我理解堆栈的递增/递减。我仍然对间接寻址有点迷茫,无法完全理解代码以了解它打印的内容。顺便说一句,您不需要在.COM和.EXE程序开始时显式加载
    SS
    SP
    。DOS负责加载
    SS:SP
    。此外,应该使用适当的堆栈段定义或特殊关键字(如果汇编程序支持任何关键字)设置堆栈大小。ESP不应加载任意硬编码值,必须为堆栈保留空间。顺便说一句,您不需要在.COM和.EXE程序的开头显式加载
    SS
    SP
    。DOS负责加载
    SS:SP
    。此外,应该使用适当的堆栈段定义或特殊关键字(如果汇编程序支持任何关键字)设置堆栈大小。ESP不应加载任意硬编码值,必须为堆栈保留空间。谢谢,这对我来说是有意义的。谢谢,这对我来说是有意义的。