前回(アセンブラの勉強方法 2)の続きです。わかりづらいud2、cli、sti命令を紹介します。
初めて見ると、add、movとは違い予想しづらい命令ですが、簡単で知っていればダンプからソースのどの箇所か特定するときの助けにもなります。
まずはud2命令ですが、この命令はBUG(),BUG_ON()などで使用される命令で、パニックさせます。
free_buffer_head()を例にして見てみます(Linuxカーネル2.6.19の場合)。
<fs/buffer.c>
void free_buffer_head(struct buffer_head *bh) { BUG_ON(!list_empty(&bh->b_assoc_buffers)); ・・・(1) kmem_cache_free(bh_cachep, bh); get_cpu_var(bh_accounting).nr--; recalc_bh_state(); put_cpu_var(bh_accounting); } |
# objdump -d vmlinux ・・・・ c0184731 <free_buffer_head>: c0184731: 89 c2 mov %eax,%edx c0184733: 8d 40 28 lea 0x28(%eax),%eax c0184736: 39 42 28 cmp %eax,0x28(%edx) c0184739: 74 08 je c0184743 <free_buffer_head+0x12> c018473b: 0f 0b ud2a ・・(1) c018473d: 8b 0b mov (%ebx),%ecx c018473f: dc 34 33 fdivl (%ebx,%esi,1) c0184742: c0 a1 a0 35 4a c0 e8 shlb $0xe8,0xc04a35a0(%ecx) c0184749: 10 11 adc %dl,(%ecx) c018474b: fe (bad) c018474c: ff (bad) ・・・・ |
objdumpコマンドでは"ud2a"と表示されていますが、これがBUGコールになります。
下記のとおりBUG_ON()のコードからud2命令を実行します。
<include/asm-generic/bug.h>
#ifndef HAVE_ARCH_BUG_ON #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) #endif |
<include/asm-i386/bug.h>
#define BUG() __asm__ __volatile__("ud2\n") |
ud2a があればBUG()コールしているとすぐわかります。
次の例はsti,cli命令です。
<kernel/softirq.c>
int on_each_cpu(void (*func) (void *info), void *info, int retry, int wait) { int ret = 0;
preempt_disable(); ret = smp_call_function(func, info, retry, wait); local_irq_disable(); ・・・(2) func(info); local_irq_enable(); preempt_enable(); ・・・(3) return ret; } |
local_irq_enable/disable()で割り込み,許可になります。
# objdump -d vmlinux ・・・・ c0129e5a <on_each_cpu>: c0129e5a: 57 push %edi c0129e5b: 89 c7 mov %eax,%edi c0129e5d: 56 push %esi c0129e5e: 89 d6 mov %edx,%esi c0129e60: 53 push %ebx c0129e61: 83 ec 04 sub $0x4,%esp c0129e64: 8b 44 24 14 mov 0x14(%esp),%eax c0129e68: 89 04 24 mov %eax,(%esp) c0129e6b: 89 f8 mov %edi,%eax c0129e6d: e8 70 cc fe ff call c0116ae2 <smp_call_function> c0129e72: 89 c3 mov %eax,%ebx c0129e74: fa cli ・・(2) c0129e75: 89 f0 mov %esi,%eax c0129e77: ff d7 call *%edi c0129e79: fb sti ・・(3) c0129e7a: 5a pop %edx c0129e7b: 89 d8 mov %ebx,%eax c0129e7d: 5b pop %ebx c0129e7e: 5e pop %esi c0129e7f: 5f pop %edi c0129e80: c3 ret ・・・・ |
<include/linux/irqflags.h>
#ifdef CONFIG_TRACE_IRQFLAGS ・・・・ #else # define trace_hardirqs_on() do { } while (0) # define trace_hardirqs_off() do { } while (0) ・・・・ #endif
#define local_irq_enable() \ do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0) #define local_irq_disable() \ do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) |
<include/asm-i386/irqflags.h>
static inline void raw_local_irq_disable(void) { __asm__ __volatile__("cli" : : : "memory"); ・・・・(2) }
static inline void raw_local_irq_enable(void) { __asm__ __volatile__("sti" : : : "memory"); ・・・・(3) } |
これでダンプを見ていて「ud2」「cli」「sti」などがあってもすぐにBUG、割り込みだとわかりますし、ダンプからソースのどの箇所か特定するときの助けにもなります。
コメント