曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5322|回复: 0
打印 上一主题 下一主题

LOCK_PREFIX

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-2-24 20:54:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
平台:X86 32位
内核:2.6.24

LOCK_PREFIX 宏在内核里随处可见,其主要用途是确保原子操作。它定义在 include/asm-x86/Alternative_32.h 中:
#ifdef CONFIG_SMP
#define LOCK_PREFIX \
        ".section .smp_locks,\"a\"\n"    \
        "  .align 4\n"            \
        "  .long 661f\n" /* address */    \
        ".previous\n"            \
               "661:\n\tlock; "

#else /* ! CONFIG_SMP */
#define LOCK_PREFIX ""
#endif
该宏的内核内容是 LOCK 指令前缀,关于 LOCK 指令前缀可以参考:http://www.groad.net/bbs/read.php?tid-3152.html


从宏的定义中,可以看到该宏主要用于 SMP 环境中。

在一些原子操作函数里可以看到该宏的应用:
static __inline__ void atomic_add(int i, atomic_t *v)
{
    __asm__ __volatile__(
        LOCK_PREFIX "addl %1,%0"
        :"+m" (v->counter)
        :"ir" (i));
}

下面将一些内核中的原子操作函数和该宏的定义都放在用户态里使用以能了解该宏的一些定义细节,程序代码如下:
#include <stdio.h>

#define LOCK_PREFIX \
        ".section .smp_locks,\"a\"\n"   \
"  .align 4\n"                  \
"  .long 661f\n" /* address */  \
".previous\n"                   \
"661:\n\tlock; "

typedef struct { int counter; } atomic_t;

#define ATOMIC_INIT(i)  { (i) }

static __inline__ void atomic_inc(atomic_t *v)
{
        __asm__ __volatile__(
                        LOCK_PREFIX "incl %0"
                        :"+m" (v->counter));
}

static __inline__ void atomic_dec(atomic_t *v)
{
        __asm__ __volatile__(
                        LOCK_PREFIX "decl %0"
                        :"+m" (v->counter));
}

static __inline__ void atomic_add(int i, atomic_t *v)
{
        __asm__ __volatile__(
                        LOCK_PREFIX "addl %1,%0"
                        :"+m" (v->counter)
                        :"ir" (i));
}


int main()
{
        atomic_t count = ATOMIC_INIT(0);
        atomic_inc (&count);
        atomic_dec (&count);
        atomic_add (1, &count);

        return (0);
}
为了简便起见,只将程序编译生成为 .o 目标文件,而不生成可执行文件:
$ gcc -c lock_prefix.c -o lock_prefix.o


使用 objdump 查看:
beyes@linux-kd1q:~/assembly> objdump -h lock_prefix.o


lock_prefix.o:     file format elf32-i386


Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000006a  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  000000a0  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  000000a0  2**2
                  ALLOC
  3 .smp_locks    0000000c  00000000  00000000  000000a0  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
  4 .comment      00000043  00000000  00000000  000000ac  2**0
                  CONTENTS, READONLY
  5 .comment.SUSE.OPTs 00000006  00000000  00000000  000000ef  2**0
                  CONTENTS, READONLY
  6 .note.GNU-stack 00000000  00000000  00000000  000000f5  2**0
                  CONTENTS, READONLY
从上面可以看到,.smp_locks 段一共有 0xc 即 12 个字节的数据。下面的分析可以观察到这些数据是什么:
beyes@linux-kd1q:~/assembly> objdump -D lock_prefix.o


lock_prefix.o:     file format elf32-i386




Disassembly of section .text:


00000000 <atomic_inc>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   8b 55 08                mov    0x8(%ebp),%edx
   9:   f0 ff 00                lock incl (%eax)
   c:   5d                      pop    %ebp
   d:   c3                      ret   


0000000e <atomic_dec>:
   e:   55                      push   %ebp
   f:   89 e5                   mov    %esp,%ebp
  11:   8b 45 08                mov    0x8(%ebp),%eax
  14:   8b 55 08                mov    0x8(%ebp),%edx
  17:   f0 ff 08                lock decl (%eax)
  1a:   5d                      pop    %ebp
  1b:   c3                      ret   


0000001c <atomic_add>:
  1c:   55                      push   %ebp
  1d:   89 e5                   mov    %esp,%ebp
  1f:   8b 45 0c                mov    0xc(%ebp),%eax
  22:   8b 55 08                mov    0x8(%ebp),%edx
  25:   8b 4d 0c                mov    0xc(%ebp),%ecx
28:   f0 01 10                lock add %edx,(%eax)
  2b:   5d                      pop    %ebp
  2c:   c3                      ret   


0000002d <main>:
  2d:   55                      push   %ebp
  2e:   89 e5                   mov    %esp,%ebp
  30:   83 ec 18                sub    $0x18,%esp
  33:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%ebp)
  3a:   8d 45 fc                lea    -0x4(%ebp),%eax
  3d:   89 04 24                mov    %eax,(%esp)
  40:   e8 bb ff ff ff          call   0 <atomic_inc>
  45:   8d 45 fc                lea    -0x4(%ebp),%eax
  48:   89 04 24                mov    %eax,(%esp)
  4b:   e8 be ff ff ff          call   e <atomic_dec>
  50:   8d 45 fc                lea    -0x4(%ebp),%eax
  53:   89 44 24 04             mov    %eax,0x4(%esp)
  57:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)
  5e:   e8 b9 ff ff ff          call   1c <atomic_add>
  63:   b8 00 00 00 00          mov    $0x0,%eax
  68:   c9                      leave  
  69:   c3                      ret   


Disassembly of section .smp_locks:


00000000 <.smp_locks>:
   0:   09 00                   or     %eax,(%eax)
   2:   00 00                   add    %al,(%eax)
   4:   17                      pop    %ss
   5:   00 00                   add    %al,(%eax)
   7:   00 28                   add    %ch,(%eax)
   9:   00 00                   add    %al,(%eax)
        ...


Disassembly of section .comment:


00000000 <.comment>:
   0:   00 47 43                add    %al,0x43(%edi)
   3:   43                      inc    %ebx
   4:   3a 20                   cmp    (%eax),%ah
   6:   28 53 55                sub    %dl,0x55(%ebx)
   9:   53                      push   %ebx
   a:   45                      inc    %ebp
   b:   20 4c 69 6e             and    %cl,0x6e(%ecx,%ebp,2)
   f:   75 78                   jne    89 <main+0x5c>
  11:   29 20                   sub    %esp,(%eax)
  13:   34 2e                   xor    $0x2e,%al
  15:   35 2e 30 20 32          xor    $0x3220302e,%eax
  1a:   30 31                   xor    %dh,(%ecx)
  1c:   30 30                   xor    %dh,(%eax)
  1e:   36 30 34 20             xor    %dh,%ss:(%eax,%eiz,1)
  22:   5b                      pop    %ebx
  23:   67 63 63 2d             arpl   %sp,0x2d(%bp,%di)
  27:   34 5f                   xor    $0x5f,%al
  29:   35 2d 62 72 61          xor    $0x6172622d,%eax
  2e:   6e                      outsb  %ds:(%esi),(%dx)
  2f:   63 68 20                arpl   %bp,0x20(%eax)
  32:   72 65                   jb     99 <main+0x6c>
  34:   76 69                   jbe    9f <main+0x72>
  36:   73 69                   jae    a1 <main+0x74>
  38:   6f                      outsl  %ds:(%esi),(%dx)
  39:   6e                      outsb  %ds:(%esi),(%dx)
  3a:   20 31                   and    %dh,(%ecx)
  3c:   36 30 32                xor    %dh,%ss:(%edx)
  3f:   39 32                   cmp    %esi,(%edx)
  41:   5d                      pop    %ebp
        ...


Disassembly of section .comment.SUSE.OPTs:


00000000 <.comment.SUSE.OPTs>:
   0:   6f                      outsl  %ds:(%esi),(%dx)
   1:   73 70                   jae    73 <main+0x46>
   3:   77 67                   ja     6c <main+0x3f>
        ...
现在再回头来看 LOCK_PREFIX 的语句:


.section .smp_locks,\"a\"\n"    \  :该条语句定义了一个名为 .smp_lock 的段,后接 "a" 属性表示 "allocatable" 。


.align 4 :该段 4 字节对其


.long 661f :.long 伪指令用来生成一个 long 型整数;现在其后接一个标号 661,那么这个整数的值则为这个标号所在处的地址(在后面看到,这个标号处存放的就是具有 lock 指令前缀的指令,所以具有 lock 指令前缀的指令地址也就是此处的值)。


.previous :后面的代码切换回到 .text 段,并将它下面的 lock 指令前缀搬移到 .text 段中。关于 .previous 伪指令的细节可参考:http://www.groad.net/bbs/read.php?tid-3150.html


从上面 objdump 反汇编所得到的代码中,蓝色部分即为 .smp_lock 段的内容,仔细观察,这些内容分别为粉红色标识的具有 lock 指令前缀的指令地址。所以,.smp_lock 段实质上就是这些指令的地址的数组。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:05 , Processed in 0.095855 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表