0から作るソフトウェア開発

日々勉強中。。。

0から作るOS開発

環境準備

環境設定

ブートローダ

カーネルローダ

GRUB

カーネル

ドライバーその他

ブートローダその8 スタック

前回までの内容

これまでで、 ということがわかりました。それでは前回の続きになりますが、スタックについて説明したいと思います

スタック

スタックの基本的な概念は英語のstackそのままで”積む”ということになります

プログラムの場合に言うスタックにはデータを積み上げることになります

ではどのように積み上げるのでしょうか

スタックにデータを積み上げる

スタックにデータを積み上げることをプッシュといいます。アセンブラ言語の命令としてPUSH命令でスタックにデータを

積み上げることができます。


	PUSH AX



この例で言いますと汎用レジスタAXの値をスタックにプッシュ(積み上げる)できます

PUSH命令でスタックに積み上げるごとにSPポインタの値は4バイトずつ減っていく

このように①PUSH AX ②PUSH BX ③PUSH CXと順番に実行した場合を考えてみます

PUSH命令を実行するたびにスタックにAX→BX→CXの値がそれぞれ積まれていきます

(Tips:順番に積み上げられていることに注意してください)

またPUSH命令が実行される度にスタックポインタSPの値が減っていきます

(上に積み上げるのでSPは減る方向に動きます)

PUSH命令を実行するとハードウェアが自動的にSPの値を減算してくれますので、

特にソフトウェアは何もしなくてもよいです(動作だけ理解できていればよいです)

スタックポインタの指すアドレスが0x0002ずつ減っていくのはなぜでしょうか

何度もでてきましたが現在このCPUが16ビットで動作しているためです

16ビットのCPUでは基本データサイズが16ビットなのでスタックの1つのデータも16ビット(2バイト)となります

ですので、スタック上にPUSHする場合は16ビットサイズが基本となります

もちろん32ビットCPU、64ビットCPUであればそれぞれ32ビット、64ビット単位でのデータ積み上げになります

(1バイトだけスタックに積みたいと思われるときもあるかもしれませんが、ハードウェアが自動的にしているのでできません)

スタックからデータを下ろす

スタックにはデータを積み上げることもできましたがデータを下ろすこともできます


	POP AX



この命令はポップ命令といい、スタックに積み上げられたデータを汎用レジスタAXに格納しています

POP命令でスタックに積み上げられたデータを下ろすことができる。SPは4バイトずつ増えていく

このように①POP CX ②POP BX ③POP AXと順番に実行したときを考えてみます

POP命令を実行するとスタックに積み上げられたデータを下ろして汎用レジスタにデータを移します

(実際にメモリ上のデータが消えるわけではありません)

この際にスタックポインタSPの値が0x0002ずつ増えていきます。

(データを下ろしているのでSPは下の方向にいきます)

このようにしてスタック上にPUSHしたデータはPOPしてデータをとることができます

その他のスタックの使い方

他にもCALL命令という命令があります

				
	CALL	Operate_CX
	XOR	CX, CX



CALL命令はC言語で言うところの関数呼び出しにあたります

CALL命令を実行するとこの例では”Operate_CX”といるうラベル付けされた関数にジャンプします

その際にハードウェアが自動的に戻りアドレスをスタックに積み上げます

この例では次の命令であるXOR命令が置いてあるアドレスをスタックに積み上げて置きます


Operate_CX:				
	ADD	CX, 0x0001
	RET



そして”Operate_CX”で関数を実行し終わった後のにRET命令を実行します

RET命令は関数の呼び出し元に戻るアドレスです。どこに戻ればいいのかが記録されているのが

CALL命令で積み上げられていたデータにあります

ですので、RET命令はスタックに積み上げられた戻りアドレスをPOPし、元の場所にジャンプして戻ることができます

CALL命令で戻りアドレスをスタックにPUSH。RET命令で戻りアドレスをPOP

その応用としてCALL命令のときに引数として渡したいデータがあるときや、関数でレジスタの値を変更したい

が戻ってきたときには元の値に戻しておきたい場合にPUSHとPOPすることもできます


	PUSH	CX			;関数から戻ってきてから元に戻したい
	PUSH	AX			;関数の引数その1
	CALL	Operate_CX
	
	POP		CX		;関数の中でCXが変更されたのでポップしてCXの値を元にもどす
	HLT	

Operate_CX:
	POP		CX		;スタックに積まれたAXの値をCXに入れる
	ADD		CX, 0x0001
	MOV		BX, CX		;足し算してBXに格納
	RET				;元にもどる



また、関数のなかでレジスタを変更するので予め使うレジスタの値をスタックへPUSHしておき

関数から戻る直前でPOPしておけば変更する前の値に戻すことができます


	CALL	Operate_CX
	

	HLT	

Operate_CX:
	PUSH	CX
	ADD		CX, 0x0001
	MOV		BX, CX		;足し算してBXに格納
	POP		CX		;関数の中でCXが変更されたのでポップしてCXの値を元にもどす
	RET				;元にもどる



これでスタックの基本的な使い方ができるようになったかと思います

では次回ブートローダの開発を進めていきましょう

inserted by FC2 system