カテゴリー「アセンブラ(nasm)」の9件の記事

2007-12-04

独習アセンブラ リスト5-2

独習アセンブラ 翔泳社の第5章のリスト 5-2です。

まず、初めに'A'をスタックに積み、
このスタックのアドレスをecxに移動します。
このecxを介して、
スタック上の値をインクリメントして、
出力してみます。


01: section .text
02: global  _start
03: 
04: _start:
05:         push    'A'
06:         mov     ebx, 1
07:         mov     ecx, esp
08:         mov     edx, 1
09: dispchr:
10:         mov     eax, 4
11:         int     0x80
12:         inc     byte [ecx]
13:         cmp     byte [ecx], 'Z' + 1
14:         jnz     dispchr
15: 
16:         pop     eax
17: 
18:         mov     eax, 1
19:         mov     ebx, 0
20:         int     0x80


5行目でスタックに'A'を積みます。
7行目ecxに'A'のスタック上のアドレスを移動します。
11行目で出力し、
12行目でecxの指すアドレスに格納されている値を
インクリメントします。
ecxはスタックのトップを指していて、
スタックのトップには'A'が格納されていたので、
これをインクリメントする事で、
スタックのトップの値が'B'となります。
14行目でdispchrにジャンプしなかった場合に
スタックからポップしてプログラムを終了します。




| | コメント (0) | トラックバック (0)

独習アセンブラ リスト5-1

独習アセンブラ 翔泳社の第5章のリスト 5-1です。

本文では、org 100hとなっているので、
ジャンプ先が100hですが、
これをLinuxで実験する勇気がないので、
似た事をやってみました。
P.174の定数の定義の項に、
$は式の含まれる行の先頭のアセンブリ位置を表します。
とありますので、$を利用して
アドレスを取得する事ができそうです。


01: section .data
02: 
03: dat     db '@'
04: 
05: section .text
06: global  _start
07: 
08: _start:
09:         push    $
10:         mov     eax, 4
11:         mov     ebx, 1
12:         mov     ecx, dat
13:         mov     edx, 1
14:         int     0x80
15:         pop     eax
16:         jmp     eax


これで、似たような事ができていると思います。
@マークを出力する無限ループとなります。
[Ctrl] + [C]キーでプログラムを中断して終了します。

まず、9行目で9行目のアドレスをスタックに積みます。
datを出力後に15行目で
スタック上の9行目のアドレスをeaxに取得します。
16行目で取得したアドレスにジャンプします。




| | コメント (0) | トラックバック (0)

2007-11-15

独習アセンブラ リスト4-4

独習アセンブラ 翔泳社の第四章のリスト 4-4です。

スタックは通常、先に積んだ物の上に
後から積む物が、上に載せられるイメージなので、
当然上の物を取り出さない限り、
下の物を取り出す事は出来ませんので、
先に積んだ物は、後から取り出す事になります。

この順序を意図的に変更する事で、
レジスタ内の値を交換します。


01: section .text
02: global  _start
03: 
04: _start:
05:         push    0x31
06: 
07:         mov     edx, 4
08:         mov     eax, 1
09: 
10:         push    edx
11:         push    eax
12: 
13:         pop     edx
14:         pop     eax
15: 
16:         mov     ebx, 1
17:         mov     ecx, esp
18:         int     0x80
19: 
20:         pop     eax
21: 
22:         mov     eax, 1
23:         mov     ebx, 0
24:         int     0x80


Linuxのシステムコールでは、
eaxに4
edxには、出力するバイト数を指定しますが、
ここでは、これを逆にします。
eax = 1
edx = 4
と指定します。

これを一度スタックに積み、
逆の順序で取り出すことで、
eaxとedxの内容を交換します。

5行目と20行目のpushとpopは、
出力される文字 '1' ( 0x31 )です。





| | コメント (0) | トラックバック (0)

独習アセンブラ リスト4-3

独習アセンブラ 翔泳社の第四章のリスト 4-3です。
XCHG命令で、ソースとディスティネーションの内容を交換します。


01: section .data
02:
03: msg     db 'Hello, assembler', 0x0a
04: len     equ $ - msg
05:
06: section .text
07: global  _start
08:
09: _start:
10:         mov     dl,  [msg]
11:         xchg    dl,  [msg + 1]
12:         mov     [msg], dl
13:
14:         mov     eax, 4
15:         mov     ebx, 1
16:         mov     ecx, msg
17:         mov     edx, len
18:         int     0x80
19:
20:         mov     eax, 1
21:         mov     ebx, 0
22:         int     0x80


10行目でdlの内容が'H'となります。
続いて11行目でdlの内容が'e'(msg + 1)
msg + 1の内容が'H'になります。
この時点でメモリ上のmsgは、
HHllo, assembler\n
となっている筈です。

12行目で、'H'([msg])にdlの内容'e'を移動するので、
メモリ上のmsgは、
eHllo, assembler\n
となりました。

あとは、出力するだけです。




| | コメント (0) | トラックバック (0)

2007-11-12

独習アセンブラ リスト4-2

独習アセンブラ 翔泳社の第四章のリスト 4-2です。
メモリのアドレスを操作する事で、
任意のデータを取得します。


01: section .data
02: 
03: msg     db 'Hello, assembler', 0x0a
04: 
05: section .text
06: global  _start
07: 
08: _start:
09:         mov     eax, [msg]
10:         push    eax
11:         mov     eax, 4
12:         mov     ebx, 1
13:         mov     ecx, esp
14:         mov     edx, 1
15:         int     0x80
16:         pop     eax
17: 
18:         mov     eax, [msg + 7]
19:         push    eax
20:         mov     eax, 4
21:         mov     ecx, esp
22:         int     0x80
23:         pop     eax
24: 
25:         mov     eax, 1
26:         mov     ebx, 0
27:         int     0x80


9行目はmsgのアドレスの値を得ます。
msgの値は、以下のような感じになっています。
msg +  0 = 'H'
msg +  1 = 'e'
msg +  2 = 'l'
msg +  3 = 'l'
msg +  4 = '0'
msg +  5 = ','
msg +  6 = ' '
msg +  7 = 'a'
msg +  8 = 's'
msg +  9 = 's'
msg + 10 = 'e'
msg + 11 = 'm'
msg + 12 = 'b'
msg + 13 = 'l'
msg + 14 = 'e'
msg + 15 = 'r'
msg + 16 = 0x0a

なので、18行目の[msg + 7]の値はaになります。

本文の例の説明には、
msgが指すメモリアドレスの文字とmsgの8番目の文字[msg + 7]を参照して、
MOVで移動するコードを含む

とあるので、一度eaxに移動してからスタックにプッシュしています。
eaxに移動しないでも、push dword [msg + 7]とする事で、
同じ事ができました。




| | コメント (0) | トラックバック (0)

2007-11-06

独習アセンブラ リスト1-4

リストの1-3は、1-2と同じような物なので、
ここでは省略します。

次は、リスト1-4です。
add命令が出てきます。
加算です。

サンプルリストでは、1 + 5を行っています。
01:  section .text
02:  global  _start
03:
04:  _start:
05:          mov     edx, 1
06:          add     edx, 5
07:          add     edx, 0x30
08:          push    edx
09:          mov     eax, 4
10:          mov     ebx, 1
11:          mov     ecx, esp
12:          mov     edx, 1
13:          int     0x80
14:          pop     edx
15:
16:          mov     eax, 1
17:          mov     ebx, 0
18:          int     0x80
まず始めに、edxを1にして
6行目、7行目で足し算をしています。
6行目の足し算は単純に5を足します。
これで、1+5の結果がedxの値となります。
7行目の足し算は文字コードの'0'を足しています。
文字コードは、'0', '1', '2', '3', '4'と並んでいます。
つまり、'0'が0x30で0x31は'1'です。
0x36は'6'になります。
数値としての6ではなく、
文字としての'6'です。
この'6'という文字を、リスト1-1と同じように
画面に出力します。

以前やったように
スタックのポインタが指すアドレスを
下のように直接操作しても問題ありません。(多分)
add     esp, 4






| | コメント (0) | トラックバック (0)

2007-10-26

独習アセンブラ リスト1-2

独習アセンブラ 翔泳社のP9, リスト1-2
文字列を出力するプログラムのLinux版です。

List 1-2
section .data

msg     db 'Hello, assembler', 0x0a
len     equ $ - msg

section .text
global  _start

_start:
        mov     eax,4
        mov     ebx,1
        mov     ecx,msg
        mov     edx,len
        int     0x80

        mov     eax,1
        mov     ebx,0
        int     0x80


基本的なコードの部分は、リスト 1-1と同じです。
ただ、セクションとして.dataという物が出てきました。
他に、本文中に説明の無いものとして、
len equ $ - msg
という行が出てきました。
本文のリストでは文字列の最後に'$'が付いていますが、
これはDOSのシステムコールに依存する物なので、
取り除き、代わりに改行コードを入れました。
0x0aが改行コード(lf)です。
equの使い方は、P174に載っています。
lenには、17が入ります。
改行コードの1バイト分も含まれている事に気をつけてください。
また、本文にあるようにlenは一度だけ評価される事に注意が必要です。

これらの定数データをデータセクションに置きます。
データセクションの開始を示すのが、section .dataです。

このプログラムは、Hello, assemblerと表示し、最後に改行して終了します。






| | コメント (0) | トラックバック (0)

2007-10-24

独習アセンブラ リスト1-1

独習アセンブラのリスト1-1をLinux版に移植してみました。
私の環境ではコンパイル、リンクは以下のようにします。
ソースファイルが1-1.asmで実行ファイル1-1を作る例です。
$ nasm -f elf 1-1.asm
$ ld -s -o 1-1 1-1.o
List1-1
section .text
global _start

_start:
    push   0x31
    mov    eax,4
    mov    ebx,1
    mov    ecx,esp
    mov    edx,1
    int    0x80
    add    esp,4

    mov    eax,1
    mov    ebx,0
    int    0x80

まず、はじめにスタックに表示する文字を積みます。
Linuxの出力のシステムコールは、
eax: 4
ebx: 1(標準出力)
ecx: 文字列の先頭のアドレス
edx: 出力する文字数
となるので、それぞれを設定します
スタックのトップを指すespを使って、
ecxには表示対象の文字のアドレスをコピーします。
int 0x80でシステムコールを使います。
add    esp,4は、
はじめにスタックに0x31が積まれているので
espの位置を元に戻しています。

最後の三行は処理終了のシステムコールです。

DOSのシステムコールは、
文字を一文字出力する場合と
末尾に'$'の付く文字列を出力する場合、
それぞれに別の命令が割当てられていますが、
Linuxでは、文字列の出力として、
一文字出力するのか、
それ以上なのかの文字数の違いのみのようです。

| | コメント (0) | トラックバック (0)

2007-10-16

アセンブラはじめました

独習アセンブラという本を購入して、
アセンブラの勉強を始めてみました。

ただ、Linux上でやってみようと思い、
チャレンジしています。

この本では、16bitのDOSがメインに書かれているので、
これを翻訳しなければなりません。

途中までは何とか似たような物を書くことができたんですが、
システムスピーカを鳴らすという部分がどうしてもできません。
C言語でのプログラムサンプルを見つけ、
コンパイルしてみるとできたのですが、
同じ事を書いているつもりでもアセンブラではできません。
セグメンテーション違反が出てしまう . . . 。
もう何日同じ事にチャレンジしているだろう。
その先の演算はできたんですが . . . 。


| | コメント (0) | トラックバック (0)