接着上面的分析:[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) |