
今回は、8086になく80186/80286で拡張されている命令の練習その3ということでPUSHA、POPA命令です。汎用レジスタマシンと言うにはレジスタ型付けが強いx86の全「汎用レジスタ」を一気にPUSH/POPする命令デス。でもスタックポインタ(SP)もPUSH/POPの対象に見えるのよ。大丈夫なのか?
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
PUSHA、POPA命令
x86は、「汎用レジスタ・マシン」というには「汎用」に?が付きそうなひんまがったアーキテクチャで有名です(個人の感想デス。)まあ、建前8本の汎用レジスタが存在してます。「スクな」とか言わないこと。登場は半世紀も前なのだから。
それら8本の「汎用」レジスタをスタックに一気にPUSH、POPするのが、PUSHAとPOPA命令です。ただし、スタック・ポインタ(SP)も汎用レジスタの1本として含まれてます。PUSHAの時にプッシュされるSPって、どんな値なの? POPAの時にSPにポップされる値で何か良からぬことが起きないの?気になって夜も眠れなくなります。大げさな。
-
- PUSHAの時にPUSHされるSPの値は、上記で SP before PUSHAの値である
- POPAの時にメモリ上のSP対応の値は読み出されるけど捨てられる
なんてこったい、SPだけはちゃんと特別扱いであります。まあ、Armが持っている複数レジスタをまとめてセーブしてくれる命令などをみてしまうと、x86のPUSHA、POPAは古色蒼然とした感じがしないでもないけど、まあ、使うときは使うよ(Armの命令は、それでもRISCか、と難癖つけたくなるケド。)
なお、PUSHA、POPAのレジスタの順番、PUSH時でならべると
AX, CX, DX, BX, SP, BP, SI, DI
という順番デス。AXの次がなぜBXでないのかは、御先祖の8ビットCPU8080に遡のぼる長い歴史あり。過去回のどこかに書いた気がします。
今回実験のプログラム
今回は以下のような処理を行ってみてます。
-
- レジスタの順番が分かるような即値を各レジスタに格納(SPだけは個別)
- PUSHAを実行(実行後、メモリ上のスタックをデバッガで確認)
- メモリ上のSP対応のメモリに「殊更な」値を書きこんで破壊
- POPAを実行(レジスタの値、特にSPについて確認)
以下は「強力なx86用アセンブラNASM」用のソースです(MSのMASMともインテルASM86とも微妙に異なるけど、まあ分かるっしょ。)
segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop prepare: mov ax, 1000h mov cx, 2000h mov dx, 3000h mov bx, 4000h mov bp, 6000h mov si, 7000h mov di, 8000h test: pusha mov bp, sp mov word [bp + 6], 5000h popa nop fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
アセンブルして実行
MS-DOS互換で機能強化されているフリーなFreeDOS上、以下のステップで上記のアセンブラソース pusha.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
nasm -f obj -l pusha.lst pusha.asm wlink name pusha.exe format dos file pusha.obj debugx pusha.exe
赤枠1個目のPUSHA直後の黄色枠内で、メモリ上にPUSHされたSP対応の値を破壊(0x5000を書き込み)してます。なお、ベースレジスタにBPを使うと、SSセグメントに対する操作となります、念のため。
さて、PUSHA前のレジスタの様子が2行目の黄色枠+赤色枠部分に。
PUSHA後のSP(レジスタ値)が緑枠に。
中ほどのメモリダンプでは、2行目の黄色枠+赤色枠部分の値がメモリ上に送られていることが分かります(順番は説明図の順番ね。)なお、繰り返しになりますが、「リトルエンディアン」なので、00 80 と書いてあったら 0x8000 のことです。また、メモリ上のSP対応部分はPUSHA前のSP値っす。
そしてピンクな0x5000 で、メモリ上のSP対応部分を「つぶして」ます。POPA後の様子が以下に。
メモリダンプのピンク部分のように「つぶされて」いますけど、POPAすると、どこ吹く風で元に戻ってます。メモリ上でSPを弄ってもダメなのよ。