- 论坛徽章:
- 0
|
本帖最后由 wangzhen11aaa 于 2011-10-11 10:54 编辑
接着上面的分析:
- 559 if (__builtin_expect (fclose (fp) != EOF, 1))
- 560 {
- 561 _IO_flockfile (stderr); /*这里好复杂*/
- 先说这个吧。
复制代码
- 1 #include <libio/libio.h>
- . . . .
- /* 先做判断,如果没有就定义一个*/
- 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、________------->* / \
复制代码 1、_____________------------->
- 我都有点怀疑,为什么简单的判断命令会出现这种神奇的东西,不废话了。接着走:
- 判断是干什么的
- 判断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可用。
复制代码
- 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
复制代码 3、_________-------->
- 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()貌似其中就有这个。我原来分析过。
复制代码 header我认为应该是个全局变量。
- 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 })
复制代码
- 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
复制代码 这里地形复杂:很抱歉把大家带进了AT&T和CPU指令集的地方。不过没有办法。
- 这里少什么呢?
- [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
复制代码
- 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 }
复制代码
- 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
- 看样子是用
复制代码- 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
复制代码
- 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
复制代码
- 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]
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,标准系统调用。 |
|