如何使用call和ret更改堆栈内容?

时间:2016-11-21 08:27:47

标签: assembly emu8086

这个代码就像图灵机的模拟一样。我正在检测这段代码,我做了一个关于改变它的每一步的表格,但我不知道如何用 CALL AND RET

来改变堆栈内容
.model small
.data
bant db 0,0,0,0,0,0,0,0,0

.code
.startup

mov si,4
call stateA
.exit

stateA proc near
cmp bant[si],0
je AB
jmp AC

AB:
mov bant[si],1
inc si
call stateB
jmp RTA

AC:
mov bant[si],1
dec si
call stateC

RTA: ret
stateA endp

stateB proc near
cmp bant[si],0
je BA
jmp BB

BA:
mov bant[si],1
dec si
call stateA
jmp RTB

BB:
mov bant[si],1
inc si
call stateB

RTB: ret
stateB endp
stateC proc near
cmp bant[si],0
je CB
jmp CHLT

CB:
mov bant[si],1
dec si
call stateB
jmp RTC

CHLT:
mov bant[si],1
inc si

RTC: ret
stateC endp

end

2 个答案:

答案 0 :(得分:2)

RET不会写入堆栈,但会修改SP。 CALL将返回地址写入堆栈,并修改SP。

您可以写入堆栈的唯一值是CALL之后的指令的IP,因此我认为不可能只使用 CALL和RET指令。

您可能需要使用MOV指令和其他指令以正常方式执行此操作。在制作堆栈帧之后,通常使用相对于[BP]的寻址模式。

答案 1 :(得分:1)

如何在堆栈顶部加载某些值的偏移量,这是一个巧妙的技巧:

    call print_message   ; address of string is pushed on top of stack
    db "some text message to print",0  ; defined inside code
print_message:
    call some_print_function ; which want single argument on stack as "ptr to string"
    ; restore stack as needed (but don't do "ret", it would execute string)

但这很有可能在32b模式下使用更多,因为推送的偏移位于代码段cs内部,因此在16b实模式下,只有代码具有单段中的所有内容才能很好地(方便地)工作和cs = ds。例如,大多数" .com"可执行文件符合此描述。

如果您的代码使用了更多的段,那么必须以通过cs:来解决该字符串的方式编写该打印例程,这不常见。