次のページ 前のページ 目次へ

4. アセンブリ & Linux - 結果 -

Linuxアセンブリプログラムを書くときそこには多くの可能性があります。はじめに どのアセンブラを使うか選べます。GAS(AS)を使うのがよいでしょう。gasは ほとんどのLinuxディストリビューションの標準となっているアセンブラです。 gasの欠点はgasがAT&T-syntaxを使っていることです。これは Intel-syntaxと大きく違っています。 DOSユーザーはほとんどがIntel-syntaxを使っています。

AT&T-syntaxについてのより詳細な情報は infoファイルにあります。このinfoファイルをhtmlフォーマットに変換しました。

Intel互換のsyntaxを参照する時はnasmでプログラムを書くことができます。

4.1 NASMの例をみてみましょう:

from the 80xxx-fidonet-area :

= deze bewaar ik : asm =================================================keepit=
from : james vahn                          17-apr-97  15:20:22  1:346/15.1
to   : jan wagemakers                                           2:292/8133.23
subj : nasm & linux
=======================================================================rem_asm=
 * 80xxx からの引用
 jw> デモがありますが、見ている範囲ではcプログラムから呼び出すように
 jw> 書かれています。nasmとlinuxで 100% アセンブリプログラムをどのように
 jw> 書くのか知りたいです。

バグフィックスされたnasm-0.94を使って、ソースを以下のようにアセンブルします。
   nasm -f elf hello.asm
   gcc hello.o -o hello
   strip hello

学ぶことがたくさんあります   :-) 


;-------------nasm's standalone hello-world.asm for linux --------
section .text
extern puts
global main

main:
   push dword msg                ;stash the location of msg on the stack.
   call puts                     ;call the 'puts' routine (libc?)
   add esp, byte 4               ;clean the stack?
   ret                           ;exit.

msg:
   db "hello world!",0

--- timed 1.01
 * origin: james vahn (jvahn@short.circuit.com) (1:346/15.1)
===============================================================================
この例ではputsの呼び出しは画面にテキストを表示するのに使われます。putsは cからのもので、Linuxでロードされるライブラリの標準表示です。しかし アセンブリでこれを行う方法もあります。interrupts です。 Linuxカーネルの今後のバージョンで変更されるかもしれないのでこの割り込み (interrupts)を使うのはお奨めしません。

4.2 gasの2つの例:

アセンブラ.028から優れたサンプルをpieter de jong氏が出しました。

例1) putsの呼び出しを使った例


 .text
message:
 .ascii "hello world!\0"
 .align 4
 .globl main
main:
 pushl %ebp
 movl %esp,%ebp
 #call ___main
 pushl $message
 call puts
 addl $4,%esp
 xorl %eax,%eax
 movl %ebp,%esp
 popl %ebp
 ret

として、
        as hello.s -o hello.o
        gcc hello.o -o hello
とコンパイルします。

例2) int 80hを使う


 .text
message:
 .ascii "hello, world!\12\0"
 .align 4
 .globl _hw
_hw:
 movl $4, %eax
 movl $1, %ebx
 movl $message, %ecx
 movl $15, %edx
 int $0x80
 movl $1, %eax
 movl $0, %ebx
 int $0x80

として、
        as hello.s -o hello.o
        ld hello.o -e _hw -o hello
        (_hw = エントリポイント)
とコンパイルします。

4.3 GASにマクロを追加する:

changed on : 5 Jul 1997

マクロを使うことによってプログラミングの複雑さをすくなくできます。ある ドキュメントで、GASはマクロを解釈できずアセンブリでマクロを使うにはGASPを 使わねばならないということを読みました。

しかし.. いくつかテストしてみたりGNU-C infoファイルを読んだところ GAS(as)を使ってアセンブリプログラムにマクロを加えることができることを 発見しました。 以下、私が行ったテストを紹介します。GAS と マクロ の可能性を試みています (訳注:dummy.dummyというファイルがあるかチェックするプログラムです)。

test_fopen.sのソース:


        .include "include.asm"

        .globl main
main:
        _print hallo            # タイトル表示
        _open bestand mode      # ファイル'dummy.dummy'を開く
        cmp $0,%eax             # Success?
        je file_error           # だめ。エラーメッセージの表示
        _close %eax             # ファイルを閉じる
        _print bestaat          # 'exist'と表示
        jmp einde               # プログラム終了
file_error:
        _print bestaat_niet     # 'doesn't exist'と表示する
einde:
        ret                     # The End ;-)

hallo:
 .string "Test Linux Program ;-) \n"
bestaat:
 .string "The file dummy.dummy exists..."
bestaat_niet:
 .string "The file dummy.dummy doesn't exist..."
bestand:
 .string "dummy.dummy"
mode:
 .string "r"

 .END

include.asm


 .MACRO _print message
 # start _print message
 pushl $\message
 call puts
 addl $4,%esp
 # end   _print message
 .ENDM

 .MACRO _open file mode
 # start _open ファイルモード
 pushl %ebp
 movl %esp,%ebp
 pushl $\mode
 pushl $\file
 call fopen
 addl $8,%esp
 movl %eax,-4(%ebp)
 # %eax = ファイルハンドル
 #        -  %eax = 0 ならファイルはない
 #        -  %eax >< 0 %eax ならファイルハンドル
 popl %ebp
 # end   _open ファイルモード
 .ENDM

 .MACRO _close filehandle
 # start _close ファイルハンドル
 pushl \filehandle
 call fclose
 addl $4,%esp
 # end   _close ファイルハンドル
 .ENDM

として、これを
        as test_fopen.s -o test_fopen.o
        gcc test_fopen.o -o test_fopen
のようにコンパイルします。

4.4 ncursesを使う

1997年7月21日 変更:

Ncurses はテキストベースのLinuxプログラムを書くときに使う関数の ライブラリです。

以下、ピュアなアセンブリプログラムからncurseesをどのように呼び出すか見る ためにサンプルプログラムを挙げます。ちゃんとしたものではないかもしれませんが 動作をみるにはよいと思います :-) 。

sat_color.s


        .include "/home/jan/assembler/include/ncurses.asm"

        .globl main
main:
        _initscr
        _start_color
        _init_pair $1,$2,$4
        _init_pair $2,$0,$6
        _init_pair $3,$3,$4
        _init_pair $4,$4,$4             # Hide the flashing cursor
                
        call cls                        # clear screen/init colors.

        _use_pair $0x00000200           # 00 00(NORMAL) 02(PAIR) 00
        _locate $1,$0
        _printw $titel
        _locate $46,$0
        _printw $pd
        _use_pair  $0x00200100          # 00 20(BOLD) 01(PAIR) 00

        _locate $32,$12
        _printw $world

        _use_pair  $0x00200300          # 00 20(BOLD) 03(PAIR) 00

        movl $0,%esi
lus:
        movb tabel(%esi),%dl            # %dl = X(%esi)
        incl %esi
        movb tabel(%esi),%cl            # %cl = Y(%esi)
        incl %esi
        cmpb $242,%cl
        jne n242_1
        movl $0,%esi
        jmp lus
n242_1:
        movl %esi,%edi
redo:
        movb tabel(%edi),%dh            # %dh = X(%esi + 1)
        incl %edi
        movb tabel(%edi),%ch            # %ch = Y(%esi + 1)
        cmpb $242,%ch
        jne  n242_2
        movl $0,%edi
        jmp redo
n242_2:
        movl $leeg,%ebp
        call print_item
        movl $linux,%ebp
        movb %ch,%cl
        movb %dh,%dl
        call print_item

        pushl $160000                   # C : usleep(....);
        call usleep                     # Wait-loop
        addl $4,%esp

        _refresh
        jmp lus
        _endwin
        ret

print_item:
        pushal
        movzbl %cl,%eax
        movzbl %dl,%ebx
        _locate %ebx,%eax
        _printw %ebp
        popal
        ret
        
cls:
        _use_pair $0x00000200           # 00 00(NORMAL) 02(PAIR) 00
                                        # Color of the first line
        movb $0,%cl
        movb $0,%dl
cls_lus:
        movl $chr32,%ebp
        call print_item
        incb %dl
        cmpb $79,%dl
        jna cls_lus
        pushal
        _use_pair  $0x00000400          # 00 00(NORMAL) 04(PAIR) 00
                                        # Color of the rest of the screen
        popal
        xorb %dl,%dl
        incb %cl
        cmpb $25,%cl
        jna cls_lus
        ret

linux:
 .string "Linux"
leeg:
 .string "     "
chr32:
 .string " "
world:
 .string "World Domination"
titel:
 .string "sat_color.s - 1997 Jan Wagemakers -"
pd:
 .string "Donated to the Public Domain :-)"
tabel:
 .include "cirkel.dat"
 .byte 242,242

 .END

(訳注:先頭のncurses.asmのインクルードディレクトリは適当に変更して下さい)

cirkel.dat


 .byte  72 , 12
 .byte  71 , 13
 .byte  69 , 15
 .byte  66 , 17
 .byte  62 , 18
 .byte  56 , 20
 .byte  51 , 21
 .byte  44 , 21
 .byte  38 , 21
 .byte  31 , 21
 .byte  24 , 21
 .byte  18 , 20
 .byte  13 , 19
 .byte  8 , 17
 .byte  5 , 16
 .byte  3 , 14
 .byte  2 , 12
 .byte  2 , 10
 .byte  3 , 8
 .byte  6 , 7
 .byte  10 , 5
 .byte  15 , 4
 .byte  20 , 3
 .byte  27 , 2
 .byte  33 , 2
 .byte  40 , 2
 .byte  47 , 2
 .byte  53 , 3
 .byte  59 , 4
 .byte  63 , 5
 .byte  67 , 7
 .byte  70 , 8
 .byte  71 , 10

/home/jan/assembler/include/ncurses.asm


 # ncurses.asm          - donated to the public domain by Jan Wagemakers -
 # derived of the following C-program
 # #include
 #
 # int main(void)
 # {
 #     initscr();  /* cursesライブラリの初期化 */
 #     move(10, 2);  /* カーソルを X: 2, Y: 10 に置く */
 #     printw("Hello, World !"); /* 表示するもの */
 #     refresh(); /* 物理画面に "Hello, World !" を置く */
 #     getch(); /* キーが押されるのを待つ */
 #     endwin(); /* deinit the curses libraries. */
 #     return 0;
 # }
 #
 # Cについてよく知らないので以下は違うこともあります。
 # 修正するときはためらわずやって下さい。
 # ncursesを使って画面に何か書きたいという時は以下のマクロを呼び出します。
 #      1. _initscr
 #      2. _locate x y  (x,y = 画面の座標)
 #      3. _printw message
 #      4. _refresh
 #      5. _endwin      (winの終り.... なにかいい響きですね ;-)

 .MACRO _initscr
 # start _initscr
 call initscr
 # end   _initscr
 .ENDM

 .MACRO _locate x y
 # start _locate x y
 pushl \x
 pushl \y
 movl stdscr,%eax
 pushl %eax
 call wmove
 addl $12,%esp
 # end   _locate x y
 .ENDM

 .MACRO _printw message
 # start _print message
 pushl \message
 call printw
 addl $4,%esp
 # end   _printw message
 .ENDM

 .MACRO _refresh
 # start _refresh
 movl stdscr,%eax
 pushl %eax
 call wrefresh
 addl $4,%esp
 # end   _refresh
 .ENDM

 .MACRO _endwin
 # start _endwin
 call endwin
 # end   _endwin
 .ENDM

# Colors と ncurses. (15/07/97)
# - After _initscr , call _start_color
# - Init with _init_pair a color-pair.
# - With _use_pair select a color-pair.

 .MACRO _start_color
 # start _start_color
 call start_color
 # end   _start_color
 .ENDM

 .MACRO _init_pair pair foreground background
 # start _init_pair
 pushl \background
 pushl \foreground
 pushl \pair
 call init_pair
 addl $12,%esp
 # end   _init_pair
 .ENDM

 .MACRO _use_pair pair
 # start _use_pair
 movl \pair,%eax
 #                |        |  %ah   |  %al   |
 # %eax = xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
 #                    |        |
 #                    |        |
 #                    |        +----> 使いたいカラーペア(color-pair)番号
 #                    +-------------> 00 = ノーマル , 20 = BOLD
 pushl %eax
 movl stdscr,%eax
 pushl %eax
 call wattr_on
 addl $8,%esp
 #end _use_pair
 .ENDM

        as sat_color.s -o sat_color.o
        gcc sat_color.o -o sat_color -lncurses
とコンパイルし、./sat_colorで実行します(訳注:このプログラムを 実行すると青い背景の画面中央に緑文字で「World Domination」、その周り を黄色文字「Linux」がぐるぐる回るデモが見れます。color_xtermなどで 実行してみて下さい)。


次のページ 前のページ 目次へ