assembly 弹出内部程序未按预期工作

lrl1mhuk  于 2023-02-16  发布在  其他
关注(0)|答案(1)|浏览(149)

我有下一个代码在TASM:

.MODEL SMALL
.STACK 128
.DATA
    msg        DB 'Message$'
    crlf       DB 0Dh, 0Ah, '$'
.CODE

print_string proc
    pop dx
    mov ah, 09h
    int 21h
    ret
print_string endp

Entry:
    mov ax, @data
    mov ds, ax
    
    push offset msg
    call print_string

    mov ax, 4c00h
    int 21h

END Entry

我有一个从堆栈中检索消息指针以进行打印的过程,但它将奇怪的符号打印到控制台中。
如果我将过程内联到如下代码中:

push offset msg
pop dx
mov ah, 09h
int 21h

它将正常工作并将我消息输出到控制台。
有人能解释一下为什么在过程中从堆栈弹出相同的值会导致非预期的行为吗?

hujrc8aj

hujrc8aj1#

pushcallpopret都影响堆栈

push offset msg
call print_string

执行这两条指令后,堆栈如下所示:

R, R, M, M, ...          R = Return address (2 bytes)
^                        M = Message pointer (2 bytes)
sp

接下来运行的指令是pop dx。堆栈现在看起来如下所示:

M, M, ...
      ^
      sp

与您的预期相反,DX寄存器现在包含call/ret指令的返回地址,这不是一个有效的消息指针,因此您会看到屏幕上出现垃圾。
ret指令运行时,它会从堆栈中弹出一些根本不是返回地址的字。

溶液1

暂时把返回地址移走,下一段代码把它弹出到AX中,我们无论如何都要清除它:

print_string proc
  pop  ax            ; return address
  pop  dx            ; message pointer (removes the argument from the stack)
  push ax            ; return address
  mov  ah, 09h
  int  21h
  ret
print_string endp

溶液2

使用堆栈帧指针。

print_string proc
  push bp            ; preserving BP
  mov  bp, sp
  mov  dx, [bp+4]    ; message pointer
  mov  ah, 09h
  int  21h
  pop  bp            ; restoring BP
  ret  2             ; remove the argument from the stack
print_string endp

因为我们希望保留BP,所以使用了push bp指令,使堆栈看起来像:

B, B, R, R, M, M, ...
^           ^
sp          |
bp          |
<--- +4 --->|

我们在新堆栈指针的偏移量**+4**处检索消息指针。

溶液3

使用堆栈帧指针。

print_string proc
  xchg bp, ax        ; preserving BP in the AX register
  mov  bp, sp
  mov  dx, [bp+2]    ; message pointer
  xchg bp, ax        ; restoring BP from the AX register
  mov  ah, 09h
  int  21h
  ret  2             ; remove the argument from the stack
print_string endp

这里我们保留了AX寄存器中的BP,代码无论如何都要清除它。堆栈如下所示:

R, R, M, M, ...
^     ^
sp    |
bp    |
< +2 >|

我们在新堆栈指针的偏移量**+2**处检索消息指针。
最后一个例子使用ret 2来移除堆栈参数,或者,您可以在参数返回给调用者后移除该参数:

push offset msg
call print_string
add  sp, 2

相关问题