ページへ戻る

− Links

 印刷 

GUIGUI01​/memo30 のバックアップソース(No.2) :: OSASK計画

osaskwiki:GUIGUI01/memo30 のバックアップソース(No.2)

« Prev[4]  Next »[5]
* ぐいぐい01に関するメモ-30
-(by [[K]], 2009.08.03)
-メモのうち重要な部分をそのうちまとめてまともなページを作る
*** (42) naskで.g01アプリを作るには?(1)
-[[impressions]]の2009-07-26ごろのfshinoさんのリクエストに答えるために、このセクションは用意されました。
-文脈的には[[GUIGUI01/memo27]]の続きだけど、あっちはC言語。こっちはアセンブラ主体です。
----
-何はともあれ、まずは文字列表示を使って"hello, world\n"をやってみることにします。・・・あれ?[[GUIGUI01/memo18]]に今から僕が書こうとしていることに近いことが書いてありますね。ああでも、今回はサイズ重視ではなく、汎用かつ簡潔性重視で行きます。
 ; ex0025.nas
 [FORMAT "WCOFF"]
 [FILE "ex0025.nas"]
 [INSTRSET "i486p"]
 [BITS 32]
         GLOBAL  _G01Main
         EXTERN  _g01_execcmd0

 [SECTION .text]

 _G01Main:
         MOV     EAX,msg
         CALL    _g01_execcmd0
         DB      0x53, 0x00     ; g01_putstr0((char *) EAX);
         RET

 [SECTION .data]

 msg     DB      "hello, world", 0x0a, 0
-これです。makeすると64バイトになるでしょう。
-要点は次の通りです。
--「CALL _g01_execcmd0 DB 0x53, 0x00」が、EAX番地からの文字列表示API
--(ポインタで指定する)文字列は.dataかもしくはスタック内に置かなければいけない。
--「CALL _g01_execcmd0」すると、ESIはある特別な値が代入され、EDIは強制的に0になる。これが困る場合は、PUSHなどでレジスタを退避すること。
--アプリの実行開始番地は_G01Mainに固定。
---他のレジスタは原則として影響がない。
-EAX以外のレジスタを指定したい場合は次の通りです。
--「CALL _g01_execcmd0 DB 0x53, 0x10」が、ECX番地からの文字列表示API
--「CALL _g01_execcmd0 DB 0x53, 0x20」が、EDX番地からの文字列表示API
--「CALL _g01_execcmd0 DB 0x53, 0x30」が、EBX番地からの文字列表示API
----
-次は1文字表示APIです。
 ; ex0026.nas
 [FORMAT "WCOFF"]
 [FILE "ex0026.nas"]
 [INSTRSET "i486p"]
 [BITS 32]
         GLOBAL  _G01Main
         EXTERN  _g01_execcmd0

 [SECTION .text]

 _G01Main:
         MOV     AL,0x20
 .putc_loop
         CALL    _g01_execcmd0
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         INC     EAX
         CMP     AL,0x7e
         JBE     .putc_loop
         MOV     AL,0x0a
         CALL    _g01_execcmd0
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         RET
-これです。makeすると57バイトになるでしょう。
-要点は次の通りです。
--「CALL _g01_execcmd0 DB 0x55, 0x16, 0x00」が、putc(EAX);相当のAPI
-ちなみにこれもレジスタを選べます。
--「CALL _g01_execcmd0 DB 0x55, 0x16, 0x10」が、putc(ECX);相当のAPI
--「CALL _g01_execcmd0 DB 0x55, 0x16, 0x20」が、putc(EDX);相当のAPI
--「CALL _g01_execcmd0 DB 0x55, 0x16, 0x30」が、putc(EBX);相当のAPI
-こんな感じで分かるでしょうか?
----
-ここで、「CALL _g01_execcmd0」の正体を明かしたいと思います。これはライブラリで用意されている関数なのですが、中身はこうなっています。
         EXTERN _g01_esi0

 _g01_execcmd0:
         XOR     EDI,EDI
         MOV     ESI,[_g01_esi0]
         JMP     [ESI]           ; これがAPI呼び出し。RETで帰ると_g01_execcmd0の呼び出し元へ帰る。
-だからEDIが0になるとか、ESIの値が上書きされるなんてことになっていたわけです。
-これを利用すると、ex0026.nasは次のように書き換えられます。
 ; ex0026.nas
 [FORMAT "WCOFF"]
 [FILE "ex0026.nas"]
 [INSTRSET "i486p"]
 [BITS 32]
         GLOBAL  _G01Main
         EXTERN  _g01_esi0

 [SECTION .text]

 _G01Main:
         MOV     AL,0x20
         XOR     EDI,EDI
         MOV     ESI,[_g01_esi0]
 .putc_loop
         CALL    [ESI]
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         INC     EAX
         CMP     AL,0x7e
         JBE     .putc_loop
         MOV     AL,0x0a
         CALL    [ESI]
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         RET
-これです。makeすると56バイトになるでしょう。ちょっとだけ小さくなったわけです。
-さらに小さくすることもできます。実は.g01アプリが実行される際には、EDI=0,ESI=[_g01_esi0]の初期値で始まることが保証されているのです。つまり、_G01Main:に入った時点でこれらの値は保証されているので、わざわざ初期化する必要はないのです。そうすると、こう書けます。
 ; ex0026.nas
 [FORMAT "WCOFF"]
 [FILE "ex0026.nas"]
 [INSTRSET "i486p"]
 [BITS 32]
         GLOBAL  _G01Main

 [SECTION .text]

 _G01Main:
         MOV     AL,0x20
 .putc_loop
         CALL    [ESI]
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         INC     EAX
         CMP     AL,0x7e
         JBE     .putc_loop
         MOV     AL,0x0a
         CALL    [ESI]
         DB      0x55, 0x16, 0x00     ; g01_putc(EAX);
         RET
-短くなりました。

* こめんと欄

#comment

« Prev[4]  Next »[5]