4

问题 :

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

代码 :

在一个外部过程中,它要求用户输入一个字符串,然后通过堆栈将其返回给主程序。

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

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

使用代码视图 4.01 和 MASM 6.11调试程序会产生以下结果:

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

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

让 SP 在循环之后最初 = 0xBA BP=0xA4(即 0xBA-0x16(字符串长度)) 在 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 在执行对 extern 过程的远调用之前是 CS:IP,并且被成功推送@SP=0xC0(即在 SS:0xBC,SS:0xBD,SS:0xBE,SS:0xBF)

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

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

我知道我可以以其他方式返回参数,但为什么会发生这种行为?

4

2 回答 2

2

SP 寄存器指示栈顶的当前位置。这个加法器下面的所有东西还没有在堆栈中。您不能使用低于 SP 的地址来存储任何数据,因为一旦任何东西被压入堆栈(例如,当产生中断时),它将被覆盖。

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

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

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

下图演示了堆栈状态:

堆

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

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

无法将数据保存在当前堆栈帧中并以这种方式从过程中返回。

于 2015-12-12T17:32:47.323 回答
2

由于您的过程MyProc的目的是通过堆栈返回一个字符串,因此您不可避免地必须将其存储在call指令压入堆栈的返回地址之上。这段代码做到了:

sub  sp, 22
call MyProc

现在,您可以简化任务并直接在堆栈上腾出的空间中输入,而不是通过 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 个字节的堆栈。如果您打算将字符串存储在堆栈中,我建议您增加此大小。

于 2015-12-13T14:36:50.510 回答