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

时间:2015-12-12 14:25:46

标签: assembly stack x86-16 procedures code-view

问题:

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

代码:

在一个extern程序中,要求用户输入一个字符串,然后通过堆栈将它返回到main。

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

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 [实际字符串在最大长度,实际计数后开始两个字节]

写入字符串中的

2- 奇怪的行为

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

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

4-Enforcing SS(即MOV SS:[BP],AL)在发生相同行为时也无能为力

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

2 个答案:

答案 0 :(得分:2)

SP寄存器指示堆栈顶部的当前位置。此加法器下面的所有内容都不在堆栈中。您不能使用SP以下的地址来存储任何数据,因为一旦将任何数据推入堆栈,它将被覆盖(例如,当生成中断时)。

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

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

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

下图显示了堆栈状态:

Stack

  1. MyProc执行的开始。
  2. 分配局部变量的空间。
  3. 复制到堆栈的字符串。
  4. 从堆栈中删除了本地变量。
  5. 发生中断:中断处理程序内的堆栈状态。
  6. 中断处理程序完成执行,返回MyProc。
  7. 从步骤4开始,用于“ABC..HJ”字符串的内存不再属于MyProc。在下一步中,该存储器用于处理中断。

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

答案 1 :(得分: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个字节。如果您打算在堆栈中存储字符串,我建议您增加此大小。