在 Extern 8086 程序中写入堆栈未通过 MOV [BP] ,AL

Writing to Stack in Extern 8086 Procedure is inactive through MOV [BP] ,AL

问题:

在外部过程中对堆栈的非活动写入

代码:

在要求用户输入字符串然后 return 通过堆栈将其发送到主程序的外部过程中。

在数据段定义的字符串与主程序文件中数据段的名称不同。

Data_segment_name_ext segment para
ORG 10H
Str  DB 20,?,20 DUP (?)
Data_segment_name_ext ends

和堆栈段声明:

Stack_segment_name segment para stack
db 64 dup(0) ;define your stack segment
Stack_segment_name ends

最初在程序开始时我声明了它 public 并将 BP 设置为 Stack top :

PUBLIC MyProc
Code_segment_name segment
MyProc PROC FAR
assume SS:Stack_segment_name,CS:Code_segment_name,DS:Data_segment_name_ext
PUSH BP 
MOV BP,SP

函数 AH=0x0A 中断 0x21 正在读取字符串

LEA DX,Str
MOV AH,0Ah
INT 21H

尝试使用以下循环将字符串保存到堆栈中:

MOV CX,22 ; The string length
MOV SI,00 ; used as an index
TRA1:
DEC BP
MOV AL,Str[SI] ; Str is defined in the data segment
MOV [BP],AL 
INC SI
LOOP TRA1

使用 code view 4.01 和 MASM 6.11 调试程序会产生以下结果:

1-字符串被正确读取并存储在DS和偏移量Str中[实际字符串从最大长度后两个字节开始,实际计数]

2-奇怪的行为在将字符串写入堆栈时:

循环BP=0xA4后让SP原本=0xBA(即0xBA-0x16(String length)) 在 SS:0xA4 处转储堆栈段显示 SS:SP 前 8 个字节的垃圾数据 并且正在写入超出此范围的正确数据。

如果 str='ABCDEFGHIJ' 只有 'GHIJ' 保存在堆栈上

>DB SS:0xA4

SS:00A4 00 00 00 00 00 00 00 00   00 00 4A 49 48 47 E7 05  ..........JIHG.. 
SS:00B4 7E 00 FD 05 02 02 00 00   0A 00 0C 06 B8 E7 05 8E  ~...............

注意:060C:000A 在执行对外部过程的远调用之前是 CS:IP 并成功推送@SP=0xC0(即在SS:0xBC、SS:0xBD、SS:0xBE、SS:0xBF)

3-将 MOV [BP],AL 替换为 MOV [BP],33h 导致相同的行为;33h 未写入旧 TOS 周围的前 8 个字节

4-Enforcing SS(即 MOV SS:[BP],AL )也无能为力,因为发生了同样的行为

我知道我可以 return 以其他方式设置参数,但为什么会出现这种情况?

SP寄存器表示栈顶的当前位置。此加法器下方的所有内容尚未在堆栈中。您不能使用低于 SP 的地址来存储任何数据,因为一旦将任何东西压入堆栈(例如,当产生中断时),它就会被覆盖。

要将局部变量存储在堆栈中,您需要递减 SP (SUB SP, 22)。这与将 22 个字节压入堆栈相同。

在过程结束时,您需要释放局部变量。为此,您需要增加 SP (ADD SP, 22)。这将从堆栈中删除 22 个字节。

完成此操作后,将无法再访问局部变量。

下图演示堆栈状态:

  1. MyProc 执行开始。
  2. space为局部变量分配。
  3. 复制到堆栈的字符串。
  4. 从堆栈中删除局部变量。
  5. 发生中断:中断处理程序内部堆栈的状态。
  6. 中断处理程序完成执行,returned 到 MyProc。

从第 4 步开始,用于 "ABC..HJ" 字符串的内存不再属于 MyProc。在下一步中,此内存用于处理中断。

无法通过过程以这种方式在当前堆栈帧中保存数据 return。

由于您的过程 MyProc 的目的是 return 通过堆栈的字符串,您不可避免地必须将其存储在推入的 return 地址之上call 指令的堆栈。此代码执行此操作:

sub  sp, 22
call MyProc

现在,您可以简化任务并直接在堆栈中空出的 space 中输入,而不是通过 DS 中的额外缓冲区输入。

mov  ax, 20
sub  sp, ax
push ax         ;This sets up the correct buffer DOS expects
call MyProc
...
MyProc PROC FAR
assume SS:Stack_segment_name,CS:Code_segment_name
PUSH BP 
MOV  BP,SP
push ds
push ss
pop  ds
lea  dx, [bp+6]
;String is being read by function AH=0x0A interrupt 0x21
MOV AH,0Ah
INT 21H
pop  ds
...

我看到你设置了一个只有 64 字节的堆栈。如果您打算在堆栈中存储字符串,我建议您增加此大小。