Chinaunix首页 | 论坛 | 博客
  • 博客访问: 303188
  • 博文数量: 94
  • 博客积分: 2163
  • 博客等级: 大尉
  • 技术积分: 932
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-20 09:23
文章存档

2012年(2)

2011年(92)

分类: LINUX

2011-10-10 15:36:10

接着上面的分析:[code]
 559                   if (__builtin_expect (fclose (fp) != EOF, 1))
 560                     {
 561                       _IO_flockfile (stderr);  /*这里好复杂*/
先说这个吧。
[/code][code]
1 #include
. . . .
/* 先做判断,如果没有就定义一个*/
   14 # undef _IO_flockfile
   15 # define _IO_flockfile(_fp) \
   16   if (((_fp)->_flags & _IO_USER_LOCK) == 0)                \/*这个判断是否被锁,这里是没有锁*1、___-->*/
   17      _IO_lock_lock (*(_fp)->_lock)    /  *重要的在这里,这里就是加锁了2、________------->* / \

[/code]1、_____________------------->[code]
我都有点怀疑,为什么简单的判断命令会出现这种神奇的东西,不废话了。接着走:

判断是干什么的
判断stderr这个文件这个是个错误输出文件,#define stderr 2 :重要性在这里。stderr,可以在编译阶段输出
这个_IO_USER_LOCK是   
#define _IO_USER_LOCK 0x8000  这是个魔数 应该代表锁的意思。
  114 /* Magic numbers and bits for the _flags field.
  115    The magic numbers use the high-order bits of _flags;
  116    the remaining bits are available for variable flags.
  117    Note: The magic numbers must all be negative if stdio
  118    emulation is desired. */
  魔数和位是为_flags域。魔数用_flags的高序位;剩下的位对于其他不同的flags可用。
[/code][code]
2、________------->
   40 #define _IO_lock_lock(_name) \  /*对此文件加锁!*/
   41   do {                                                                        \
   42     void *__self = THREAD_SELF;     /*这是宏定义获得此线程的地址3、______-------->*/                                           \
   43     if ((_name).owner != __self)        /*重要的分支从这里开始了,如果正在使用加锁的不是本线程*/                                     \
   44       {                                                                       \
   45         lll_lock ((_name).lock, LLL_PRIVATE);         /*如果不是这个线程的5、______----------->检查锁的状态*/                        \
   46         (_name).owner = __self;                                /那么加上锁的线程就可以是本线程了*/               \
   47       }                                                                       \
   48     ++(_name).cnt;      /*本锁的引用数目加1*/                                                      \
   49   } while (0)
   50
[/code]3、_________-------->[code]
nptl/sysdeps/i386/tls.h, line 262
 262 # define THREAD_SELF \   
  263   ({ struct pthread *__self;     /*建立一个数据结构*/                                           \
  264      asm ("movl %%gs:%c1,%0" : "=r" (__self)  /*输出到某个寄存器 :c 的作用是去掉返回来的$符号,gcc 扩展*/                              \
  265           : "i" (offsetof (struct pthread, header.self)));  /*获得偏移地址4 、__--->                  \
  266      __self;})

 4、_____--------->
#define offsetof(type, field)   __offsetof(type, field)
#define __offsetof(type, field)  __builtin_offsetof(type, field)

这属于gcc的扩展语法:

inuxcompiler-gcc4.h文件
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 现在有个函数叫做list_entry()貌似其中就有这个。我原来分析过。
[/code]header我认为应该是个全局变量。[code]
5、____-----------> nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h, line[code]
  286 #define lll_lock(futex, private) \                                             /*mutex为互斥量,这里的futex指文件互斥量*/
  287   (void)                                                                      \/*(void)类型
  288     ({ int ignore1, ignore2;                                                  \
  289        if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)        \  /*如果在运行时,private为给定的常数,这里显然是0因为在i386环境下LLL_PRIVATE所有架构都是0,说明没有此线程,好了,那么就出现了后面的创建和系统调用。*/
  290          __asm __volatile (__lll_lock_asm_start                               \6、_____----->/*开始为了获得zf的值*/
  291                            "jnz _L_lock_%=\n\t"                               \
  292                            ".subsection 1\n\t"                                \ /*段号是1"*/
  293                            ".type _L_lock_%=,@function\n"                     \ /*_L_lock属性是函数*/
  294                            "_L_lock_%=:\n"                                    \
  295                            "1:\tleal %2, %%ecx\n"                             \  /*取long类型的futex的,(futex是一个线程)偏移,放入了ecx寄存器*/
  296                            "2:\tcall __lll_lock_wait_private\n"               \  /*调用__lll_lock_wait_private()8、____---->*/
  297                            "3:\tjmp 18f\n"                                    \ /*跳转*/
  298                            "4:\t.size _L_lock_%=, 4b-1b\n\t"                  \  /*设置名称为_L_lock%大小为3字节*/
  299                            ".previous\n"                                      \  /*本命令交换当前段(及其子段)和最近访问过的段(及其子段)。多个连续的.previous命令将使当前位置两个段(及其子段)之间反复切换。用段堆栈的术语来说,本命令使当前段和堆顶段交换位置*/
  300                            LLL_STUB_UNWIND_INFO_3                             \ 7、_________------>

  301                            "18:"                                              \
  302                            : "=a" (ignore1), "=c" (ignore2), "=m" (futex)     \   [eax寄存器是在__lll_lock_asm_start()函数中返回的eax寄存器的值,或者是else中的那个__status值。*/
  303                            : "" (0), "1" (1), "m" (futex),                   \ /*""代表是内存变量,内存增量寻址,,ecx初始化为 0.*/
  304                              "i" (MULTIPLE_THREADS_OFFSET)                    \ /*"i"代表为立即数,所以要加上P来消除$符号*/
  305                            : "memory");                                       \
  306        else                                                                   \
  307          {                                                                    \
  308            int ignore3;                                                       \
  309            __asm __volatile (__lll_lock_asm_start                             \/*这里进行比较*/
  310                              "jnz _L_lock_%=\n\t"                             \ /*这里和zf有什么干系呢?*/
  311                              ".subsection 1\n\t"                              \  
  312                              ".type _L_lock_%=,@function\n"                   \  /*如果zf为0,就是
  313                              "_L_lock_%=:\n"                                  \
  314                              "1:\tleal %2, %%edx\n"                           \  /*将futex的有效地址放入edx寄存器*/
  315                              "0:\tmovl %8, %%ecx\n"                           \  /*将private的值存入 ecx寄存器*/
  316                              "2:\tcall __lll_lock_wait\n"                     \  /*调用锁等待*/
  317                              "3:\tjmp 18f\n"                                  \
  318                              "4:\t.size _L_lock_%=, 4b-1b\n\t"                \
  319                              ".previous\n"                                    \  /*段之间可以方便切换*/
  320                              LLL_STUB_UNWIND_INFO_4                           \
  321                              "18:"                                            \
  322                              : "=a" (ignore1), "=c" (ignore2),                \
  323                                "=m" (futex), "=&d" (ignore3)                  \
  324                              : "1" (1), "m" (futex),                          \
  325                                "i" (MULTIPLE_THREADS_OFFSET), "" (0),        \
  326                                "g" (private)                                  \
  327                              : "memory");                                     \
  328          }                                                                    \
  329     })
[/code][code]
6、___________---------> nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
  278 # define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %1, %2\n\t"  
  279 #else
  280 # define __lll_lock_asm_start "cmpl $0, %%gs:%P6\n\t"                         \ /*去掉$符号,这个%%gs: %P6 ,gs是执行t*/
  281                               "je 0f\n\t"                                     \ /*如果是0,那么跳标记0
  282                               "lock\n"                                        \
  283                               "0:\tcmpxchgl %1, %2\n\t"          /*比较并交换指令见博客分析,最后获得的值等效于%2的值存入eax寄存器返回,%2就是futex即是锁的值,但是重点在如果eax中的数如果和%2中的相等,会将zf置1,并且将%1里面的 1 赋给futex。并且会把锁的值清零。否则,就是zf清零,直接将%2的值装入eax(那里代表着ignore1)。这将影响到后面的分支。*/
  284#endif
7、______________---------->
  174 #define LLL_STUB_UNWIND_INFO_3 \
  175 LLL_STUB_UNWIND_INFO_START                                      \
  176 "10:\t" ".byte  0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"        \
  177 LLL_STUB_UNWIND_INFO_END
[/code]这里地形复杂:很抱歉把大家带进了AT&T和CPU指令集的地方。不过没有办法。[code]
这里少什么呢?                  
                 [color=Blue] 就是创建这是在创建锁,文件名是lowlevellock.h不过我没有弄明白这个格式*/[/color]
 122 #define LLL_STUB_UNWIND_INFO_START \                      
  123         ".section       .eh_frame,\"a\",@progbits\n"            \   /*当目标格式为ELF时,.section命令应如下使用:
.section name [, "flags"[, @type]].eh_frame为段名称  中间的a代表allocated,progbits代表包含数据的段*/
  124 "5:\t"  ".long  7f-6f   # Length of Common Information Entry\n" \  /*长度为标号7到标号6之间的长度*/
  125 "6:\t"  ".long  0x0     # CIE Identifier Tag\n\t"               \  /*这里是赋值标记*/
  126         ".byte  0x1     # CIE Version\n\t"                      \ /*还有版本!*/
  127         ".ascii \"zR\\\"       # CIE Augmentation\n\t"         \  /*增强字符*/
  128         ".uleb128 0x1   # CIE Code Alignment Factor\n\t"        \ /*unsigned little endian base 128 (低地址结尾的无符号128位基数)。这是一个紧凑的,变长的数字表示方法,当使用DWARF符号调试格式时使用,这里看来是目标代码对齐。*/
  129         ".sleb128 -4    # CIE Data Alignment Factor\n\t"        \signed little endian base 128”(低地址结尾的带符号128位基数)。这是一个紧凑的,变长的数字表示方法,当使用DWARF符号调试格式时使用,这里是数据对齐*/
  130         ".byte  0x8     # CIE RA Column\n\t"                    \/*编译成下一个字节,是其本身0x8*/
  131         ".uleb128 0x1   # Augmentation size\n\t"                \ /*段长增加长度,是可变化的*/
  132         ".byte  0x1b    # FDE Encoding (pcrel sdata4)\n\t"      \ /*FED编码,google Frequency Domain Ecoding*/
  133         ".byte  0xc     # DW_CFA_def_cfa\n\t"                   \ 334 #define DW_CFA_def_cfa          0x0c
  134         ".uleb128 0x4\n\t"                                      \
  135         ".uleb128 0x0\n\t"                                      \
  136         ".align 4\n"                                            \/*以4字节对齐,这些数据应该是通用的*/
  137 "7:\t"  ".long  17f-8f  # FDE Length\n"                         \  /PDF长度*/
  138 "8:\t"  ".long  8b-5b   # FDE CIE offset\n\t"                   \  /偏移地址,就是前面的值8-5之间的长度*/
  139         ".long  1b-.    # FDE initial location\n\t"             \  /*初始化位置前面的标记1到 一个标记为.的位置*/
  140         ".long  4b-1b   # FDE address range\n\t"                \ /*地址长度范围在3字节范围之内*/
  141         ".uleb128 0x0   # Augmentation size\n\t"                \  
  142         ".byte  0x16    # DW_CFA_val_expression\n\t"            \ /*这是个和上面都是指令框架操作码*/
  143         ".uleb128 0x8\n\t"                                      \
  144         ".uleb128 10f-9f\n"                                     \ /*由于
  145 "9:\t"  ".byte  0x78    # DW_OP_breg8\n\t"                      \ /*同上*/
  146         ".sleb128 3b-1b\n"
  147 #define LLL_STUB_UNWIND_INFO_END \
  148         ".byte  0x16    # DW_CFA_val_expression\n\t"            \
  149         ".uleb128 0x8\n\t"                                      \
  150         ".uleb128 12f-11f\n"                                    \
  151 "11:\t" ".byte  0x78    # DW_OP_breg8\n\t"                      \
  152         ".sleb128 3b-2b\n"                                      \
  153 "12:\t" ".byte  0x40 + (3b-2b-1) # DW_CFA_advance_loc\n\t"      \
  154         ".byte  0x16    # DW_CFA_val_expression\n\t"            \
  155         ".uleb128 0x8\n\t"                                      \
  156         ".uleb128 16f-13f\n"                                    \
  157 "13:\t" ".byte  0x78    # DW_OP_breg8\n\t"                      \
  158         ".sleb128 15f-14f\n\t"                                  \
  159         ".byte  0x0d    # DW_OP_const4s\n"                      \
  160 "14:\t" ".4byte 3b-.\n\t"                                       \
  161         ".byte  0x1c    # DW_OP_minus\n\t"                      \
  162         ".byte  0x0d    # DW_OP_const4s\n"                      \
  163 "15:\t" ".4byte 18f-.\n\t"                                      \
  164         ".byte  0x22    # DW_OP_plus\n"                         \
  165 "16:\t" ".align 4\n"                                            \
  166 "17:\t" ".previous\n"   /*这里真是水平有限了,好多伪代码。像是在构建一个.elf文件吧*/
  167
[/code][code]
8、__________-------->
 28 __lll_lock_wait_private (int *futex)   /*前面创建创建锁,判断如果futex互斥锁值为1,那么old就返回1*/
   29 {
   30   do
   31     {  
   32       int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); 9、________------>/*
   33       if (oldval != 0)  /*如果futex所指向的那个值不等于0那么old就不是0*/
           /*
   34         lll_futex_wait (futex, 2, LLL_PRIVATE);  10、____________----------->/*如果不是0,锁等待。*/
   35     }
   /*如果返回0,就说明futex没有被锁,就给它上锁为2,并退出循环*/
   36   while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); 11、__________---------->
   37 }
[/code][code]
9和11在下面
   27 /* The only basic operation needed is compare and exchange.  */
   28 #define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \  /*mem是int *类型*/
   29   ({ __typeof (mem) __gmemp = (mem);                                  \ /*定义个__gmemp类型是int类型*/
   30      __typeof (*mem) __gret = *__gmemp;                               \ /*将mem的值赋值给__gret*/
   31      __typeof (*mem) __gnewval = (newval);                            \ /*定义__gnewval为int 类型,数值为newval,就是2*/
   32                                                                       \
   33      if (__gret == (oldval))       /*如果当前锁的值和old向等,那么就说明上锁了。返回1。并改变锁的值为2。此时futex指向的锁变成了2 ,后得,wait锁打开,接着循环。*/              \
   34        *__gmemp = __gnewval; /*gmemp: pointer*/                                         \
   35      __gret; })    /* gret:*/
   36
   37 #define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
   38   ({ __typeof (mem) __gmemp = (mem);                                  \ /*gmemp为int *类型*/
   39      __typeof (*mem) __gnewval = (newval);                            \ /*将新值newval 赋给__gnewval*/
   40                                                                       \
   41      *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })  futex锁值为0时,会给他上锁,并停止循环*/
   42
   43 #endif  
 看样子是用
[/code][code]10、_______________--------------->
  198 #define lll_futex_wait(futex, val, private) \  /*根据前面的LLL_PRIVATE:private定义为0*/
  199   lll_futex_timed_wait (futex, val, NULL, private)
  200
  201
  202 #define lll_futex_timed_wait(futex, val, timeout, private) \    val为2,timeout : 0, private  ; 0;
  203   ({                                                                          \
  204     int __status;                                                             \
  205     register __typeof (val) _val asm ("edx") = (val);                         \  /*_val是edx内的变量*/
  206     __asm __volatile (LLL_EBX_LOAD                                            \  
  207                       LLL_ENTER_KERNEL                                        \
  208                       LLL_EBX_LOAD                                            \
  209                       : "=a" (__status)                                       \
  210                       : "" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout),  \
  211                         "c" (__lll_private_flag (FUTEX_WAIT, private)),       \
  212                         "d" (_val), "i" (offsetof (tcbhead_t, sysinfo))       \
  213                       : "memory");                                            \
  214     __status;      /*返回的是最后的这个__status值,如果系统调用成功那么就会返回0*/    \
  215   })
  216
[/code][code]
  100 #ifdef PIC 如果定义了PIC微指令控制器
  101 # define LLL_EBX_LOAD   "xchgl %2, %%ebx\n"  /*将寄存器D中的futex装载到ebx寄存器*/
  102 # define LLL_EBX_REG    "D"  
  103 #else
  104 # define LLL_EBX_LOAD
  105 # define LLL_EBX_REG    "b"  /*否则就就直接装载到ebx寄存器*/
  106 #endif
[/code][code]
  108 #ifdef I386_USE_SYSENTER /*I386*/
  109 # ifdef SHARED    是否定义了共享 ,如果是就调用sysinfo的偏移地址进入进程空间
  110 #  define LLL_ENTER_KERNEL      "call *%%gs:%P6\n\t"
  111 # else
  112 #  define LLL_ENTER_KERNEL      "call *_dl_sysinfo\n\t" /*12、_______------>直接调用*/
  113 # endif
  114 #else
  115 # define LLL_ENTER_KERNEL       "int $0x80\n\t"
  116 #endif
[/code][code]
12、______------>
 142 uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;

   50 # define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80 /*想往系统调用里面走,我就不怕了*/
   49 extern void _dl_sysinfo_int80 (void) attribute_hidden;
这里就进入系统调用int80,标准系统调用。
阅读(1593) | 评论(0) | 转发(0) |
0

上一篇:at&t伪指令

下一篇:cat/proc / maps = 分析

给主人留下些什么吧!~~