ikj78i 發表於 2024-11-22 08:17:36

堆疊的應用

本帖最後由 ikj78i 於 2024-11-22 08:21 編輯

堆疊是記憶體中的一塊區域,程式一開始執行時,系統會保留一塊記憶體給堆疊使用。等所有
初始化工作完成,ESP就指向堆疊某處,此位址及比此位址高的記憶體存有系統保留的資料,
比這個位址低的記憶體空間都是空的。此為指稱為堆疊頂。
x86 CPU利用PUSH指令把資料存入堆疊,它的語法是
  PUSH 來源運算元
  來源運算元可以是暫存器、變數、常數
每當PUSH來源運算元時,ESP會先減少,然後再把來源運算元存入ESP所指的位址。至於減少多
少,要看來源運算元長度。如果是WORD就減少2;如果;是DWORD就減少4。而此時堆疊頂就比原
先少2或少4。像這樣把資料存入堆疊使ESP減少稱為把資料推入堆疊。
而讀取堆疊的資料則用x86指令
  POP 目的運算元
  目的運算元只能是暫存器、變數
當POP目的運算元時,先把ESP所指的堆疊頂資料存入目的運算元,再使ESP增加。增加多少跟
目的運算元的長度有關。這樣的過程稱為彈出資料。
舉例來說,假如有底下三個指令,X、Y、Z都是字組,ESP為106
      堆疊位址 低-->高
指令     ESP 100 102 104 106
PUSH X  106             DDD 尚未執行PUSH X
PUSH Y  104          X  DDD 尚未執行PUSH Y,而PUSH X已執行完畢
PUSH Z  102      Y   X  DDD 尚未執行PUSH Z,而PUSH Y已執行完畢
        102  Z   Y   X  DDD PUSH Z已執行完畢
假如現在要把上面三個堆疊的資料依序彈出,且存於位址300處
指令   ESP 100 102 104 106....300 302 304 306
POP 100  Z   Y   X  DDD                    尚未執行POP
POP 102      Y   X  DDD     Z              尚未執行POP ,已執行POP
POP 104          X  DDD     Z   Y          尚未執行POP ,已執行POP
          106             DDD     Z   Y   X      已執行完POP
堆疊有一種很特別的性質,最先推入堆疊的資料,卻是最後才能彈出。上面的例子X是最先推入
堆疊,再彈出後卻是在最高位址。由於堆疊有這種特性,很適合把資料做倒敘排列(就是先後順
序顛倒)
回文詩是中文特有的詩體,正讀與倒讀都有意義,例如底下的例子:;底下的PALINDROME.ASM把宋朝李禺兩相思的正文夫思妻,回文後變妻思夫
;此程式利用堆疊先進後出的特性就能造成回文詩的效果。
.586
.model  flat,stdcall
option  casemap:none
include    c:\masm32\include\windows.inc
include    c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
;*******************************************************************************
.DATA
hOut    DD      ?
dOut    DD      ?
author  DB      "《兩相思》 宋 李禺",0dh,0ah
poem    DB      "枯眼遙望山隔水,往來曾見幾心知。",0dh,0ah
        DB      "壺空怕酌一杯酒,筆下難成和韻詩。",0dh,0ah
        DB      "途路阻人離別久,訊音無雁寄回遲。",0dh,0ah
        DB      "孤燈夜守長寥寂,夫憶妻兮父憶兒。",0dh,0ah
palindromed     DB      0dh,0ah,"回文後:",0dh,0ah
poem_size       EQU     OFFSET palindrome_poem-OFFSET author
poem_text_size  EQU     OFFSET palindromed-OFFSET poem
palindrome_poem DB      poem_text_size+4 DUP (0)
;*******************************************************************************
.CODE
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
main    PROC
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
        mov     hOut,eax
        invoke  WriteConsole,hOut,OFFSET author,poem_size,OFFSET dOut,0
    ;把正文推入堆疊
        lea     edx,poem
        mov     ecx,17*4        ;每列包含標點符號及換行符號共17個字組,有4列
next1:  push    WORD PTR   ;從peom字串的第一個字組推入堆疊,它在堆疊最高位址
        add     edx,2           ;而後依次把下個字組推入堆疊,存放位址越來越低
        loop    next1
    ;由堆疊中取回(彈出)詩文,存放於palindrome_poem
        mov     ecx,17*4        ;堆疊內已存放17*4個字組
        lea     edx,palindrome_poem ;資料由堆疊彈出後的存放位址
next2:  pop     WORD PTR       ;彈出一個字組,存放於EDX所指的位址
        add     edx,2               ;每彈出一個堆疊,EDX所指位址往後增加2
        loop    next2
    ;處理每列最後面的標點符號及換行符號,它們必須交換位置
        mov     ecx,3
        lea     edx,palindrome_poem
        add     edx,34
next3:  mov     ax,
        xchg    ax,
        mov     ,ax
        add     edx,34
        loop    next3
    ;處理最後一行的句號
        mov     WORD PTR,043a1h
        invoke  WriteConsole,hOut,OFFSET palindrome_poem+4,poem_text_size,OFFSET dOut,0
        invoke  ExitProcess,0
main    ENDP
;*******************************************************************************
END     main依下面步驟組譯、連結並執行:

頁: [1]
查看完整版本: 堆疊的應用