在 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 个字节。
完成此操作后,将无法再访问局部变量。
下图演示堆栈状态:
- MyProc 执行开始。
- space为局部变量分配。
- 复制到堆栈的字符串。
- 从堆栈中删除局部变量。
- 发生中断:中断处理程序内部堆栈的状态。
- 中断处理程序完成执行,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 字节的堆栈。如果您打算在堆栈中存储字符串,我建议您增加此大小。
问题:
在外部过程中对堆栈的非活动写入
代码:
在要求用户输入字符串然后 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 个字节。
完成此操作后,将无法再访问局部变量。
下图演示堆栈状态:
- MyProc 执行开始。
- space为局部变量分配。
- 复制到堆栈的字符串。
- 从堆栈中删除局部变量。
- 发生中断:中断处理程序内部堆栈的状态。
- 中断处理程序完成执行,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 字节的堆栈。如果您打算在堆栈中存储字符串,我建议您增加此大小。