アセンブラの勉強方法 2
前回(アセンブラの勉強方法)のテストプログラムではmov、cmp、jmp、add命令など見ることができましたが、少し足りないのでもう少し見てみます。
今回のテストプログラムでは関数コールをしてみます。
あとはわかりづらいインラインアセンブラも入れてみます。逆アセンブラすればインラインアセンブラもなんとなくわかります。
前回と同じようにテストプログラムを作成して、コンパイルします。( Fedora Core 5 32bit の場合 )
| # cat assemble2.c #include <stdio.h> /* * include/asm-i386/atomic.h */ #ifdef CONFIG_SMP #define LOCK "lock ; " ・・・・(4) #else #define LOCK "" #endif typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } static __inline__ void atomic_inc(atomic_t *v) ・・・・(7) { __asm__ __volatile__( LOCK "incl %0" ・・・・(3) assembler template :"=m" (v->counter) ・・・・(5) output operand :"m" (v->counter)); ・・・・(6) input operand } int func(atomic_t *cnt) { atomic_inc(cnt); ・・・・(3) return 0; } int main(void) { atomic_t cnt=ATOMIC_INIT(0); ・・・・(1) func(&cnt); ・・・・(2) return 0; } |
インラインアセンブラの例としてLinuxカーネル(2.6.15)のinclude/asm-i386/atomic.h からatomic_inc()をそのままコピーしています。コンパイルは-DオプションでCONFIG_SMPを有効にします。
| # gcc -Wall -O0 -DCONFIG_SMP assemble2.c -o assemble2 # ls assemble2.c assemble2 # objdump -d assemble2 ・・・・ 08048354 <func>: 8048354: 55 push %ebp 8048355: 89 e5 mov %esp,%ebp 8048357: 83 ec 08 sub $0x8,%esp 804835a: 8b 45 08 mov 0x8(%ebp),%eax 804835d: 89 04 24 mov %eax,(%esp) 8048360: e8 07 00 00 00 call 804836c <atomic_inc> ・・(7) 8048365: b8 00 00 00 00 mov $0x0,%eax 804836a: c9 leave 804836b: c3 ret 0804836c <atomic_inc>: 804836c: 55 push %ebp 804836d: 89 e5 mov %esp,%ebp 804836f: 8b 55 08 mov 0x8(%ebp),%edx ・・(5) 8048372: 8b 45 08 mov 0x8(%ebp),%eax ・・(6) 8048375: f0 ff 02 lock incl (%edx) ・・(3)(4) 8048378: 5d pop %ebp 8048379: c3 ret 0804837a <main>: 804837a: 8d 4c 24 04 lea 0x4(%esp),%ecx 804837e: 83 e4 f0 and $0xfffffff0,%esp 8048381: ff 71 fc pushl 0xfffffffc(%ecx) 8048384: 55 push %ebp 8048385: 89 e5 mov %esp,%ebp 8048387: 51 push %ecx 8048388: 83 ec 14 sub $0x14,%esp 804838b: c7 45 f8 00 00 00 00 movl $0x0,0xfffffff8(%ebp) ・・(1) 8048392: 8d 45 f8 lea 0xfffffff8(%ebp),%eax 8048395: 89 04 24 mov %eax,(%esp) 8048398: e8 b7 ff ff ff call 8048354 <func> ・・(2) 804839d: b8 00 00 00 00 mov $0x0,%eax ・・[1] 80483a2: 83 c4 14 add $0x14,%esp 80483a5: 59 pop %ecx 80483a6: 5d pop %ebp 80483a7: 8d 61 fc lea 0xfffffffc(%ecx),%esp 80483aa: c3 ret 80483ab: 90 nop ・・・・ |
(1)でatomic変数を初期化しています。
(2)でfunc()を呼び出し(call)しています。call命令とjmp命令の違いですが、jmpはジャンプして終わりですが、callはまた戻ってきます。call命令の場合はスタックポインタespに戻るアドレスを保存します。
この場合[1]の"804839d"がespに残ります。(注1)
(3)はインラインアセンブラの最初の命令です。gccオプションに"-D"オプションを指定したので(4)のlockプレフィックスが付いてアトミック操作になります。
(5)、(6)がわからないところですが、(5)はoutput operandだそうです。"="はoutputを意味します。
"m"はmemory operandだそうです。アトミック変数をローカルでスタックに定義しているので当然ですがメモリです。
(6)はeaxレジスタに一時的に読み出しています。意味がなさそうです。というのも(3)で%0しか使っていません。(注2)
%0はoperand numberで最初(0番目)のオペランドの意味です。今回でいうと0番目は(5)です。(6)は%1ですが%1は使っていません。
(3)はgccマニュアルでassembler templateとありオペランドではないみたいです。
gccマニュアルはhttp://gcc.gnu.org/onlinedocs/からダウンロードできます。
今回は以下を参考にしました。
5.34 Assembler Instructions with C Expression Operands
The `=' in `=f' indicates that the operand is an output5.35.1 Simple Constraints
`m'
A memory operand is allowed, with any kind of address that the machine
supports in general.`0', `1', `2', ... `9'
An operand that matches the specified operand number is allowed.
(7)ではatomic_inc()が__inline_で宣言されているのでのですが、call命令で関数コールされています。これはコンパイルのときに最適化オプションをオフ(-O0)にしているのが原因です。-O2オプションでコンパイルすると以下のようにインラインになります(func()関数の中にatomic_inc()が組み込まれます)。
| # gcc -Wall -O2 -DCONFIG_SMP assemble2.c -o assemble2 # objdump -d assemble2 ・・・・ 08048360 <func>: 8048360: 55 push %ebp 8048361: 89 e5 mov %esp,%ebp 8048363: 8b 45 08 mov 0x8(%ebp),%eax 8048366: f0 ff 00 lock incl (%eax) 8048369: 5d pop %ebp 804836a: 31 c0 xor %eax,%eax 804836c: c3 ret 804836d: 8d 76 00 lea 0x0(%esi),%esi ・・・・ |
(注1):ダンプのバックトレースなどでは[1]のようにcall命令の次のアドレスが表示されます。
実際には1行上のcall命令を実行したことになります。
(注2):ちなみに2.6.19ではコードが変更されていおり、無駄のないコードとなっていました。
以下のatomic_inc()のコードに変更して-O0でコンパイルすると(6)が消えました(下記参照)。
(カーネルのコンパイルは-O2で最適化されるので特に影響はありません)
static __inline__ void atomic_inc(atomic_t *v)
{
__asm__ __volatile__(
LOCK_PREFIX "incl %0"
:"+m" (v->counter));
}
| ・・・・ 0804836c <atomic_inc>: 804836c: 55 push %ebp 804836d: 89 e5 mov %esp,%ebp 804836f: 8b 45 08 mov 0x8(%ebp),%eax 8048372: f0 ff 00 lock incl (%eax) 8048375: 5d pop %ebp 8048376: c3 ret ・・・・ |




コメント