未经允许,拒绝转载
这篇文章综合了目前我在编译原理,linux内核,以及其它涉及计算机方面的认识。推荐书籍:UTL(深入理解linux内核),龙书,linkers and loaders,以及一个国产的编译原理透视,csapp也行不过感觉在内核方面不怎么深入。我将尽可能不过多深入细节,因为一旦深入细节估计我几十篇博客都说不完,我只对整个框架作探讨。
在你编程的时候你有考虑过你写的东西在计算机上是怎么布置和运行的吗?我可以用一组形象的比喻来帮助你了解整个程序运行的计算机各个方面的参与,看完过后希望你可以像我一样对整个计算机软件架构组成感到不可思议以及那深深地敬仰。
从你编写的程序(你所输入的是ASII码)到计算机能识别的目标文件是编译器的事,而后链接器把多个目标文件及.o文件以及一些动态库给链接成一个能在内核里面执行的可执行文件。形象的比喻是你就像是一个铁路铁轨的规划师,编译器负责按照你的规划造铁轨,造完后链接器把它装上去,内核的控制流才能控制CPU及火车在你的铁路上跑(我这控制流的比喻是有深意的,稍后看完就知道),对于c语言这种结构化的语言(在我看来是面向内存的语言)来说,结构是核心,及“{}”这个是核心,在这用代码举个例子:
#include
#include
int sum(int num,...){return num;}
int i;
int main()
{
i =9;
__int16 * str2=L"1223";
char * str3=L"1223";
printf("do you know?\n%s %d %d\n",str2,*(str2+1),*(str3+1));
{i=2;}{int i=3;}{int i=4;}
printf("%d",i);
return 0;
}
让我来解释解释,所有数据都用一个标识符表示,在词法分析时会生成一个token也及一个词法单元每个词法单元都会有一些可选的属性值,词法分析是怎么分析的呢,用的是有穷自动机算法来做状态机(每种类型比如说 空白键,无符号数字都是一个状态转移图,有穷自动机就是匹配这些状态的一种算法),有穷自动机算法会匹配各个词素而词素(也就是有意义的字符串)就是词法单元的一个实例,比如说
int i
词法分析编译器扫到i这个字母时会往下继续一直遇到分隔符(空格换行符这些),得到int这个字符串(其中还有一些加快分析的方法比如说用缓冲区对),恰好是个保留字(keyword,系统预定义在GCC一个函数里面有,因为函数名比较长我忘记了 不过我为啥知道用L在字符串之前也是看gcc源代码知道的)于是这个词素的类型就是CST__INT(反正是系统预定义的),而后遇到i,这个不是特殊保留字于是把它当作标识符并生成类似于int i;
int main()
{
i =9;
__int16 * str2=L"1223";
char * str3=L"1223";
printf("do you know?\n%s %d %d\n",str2,*(str2+1),*(str3+1));
{i=2;}{int i=3;}{int i=4;}
printf("%d",i);
return 0;
}
int i中的i是这个程序的顶层作用域,main函数为其子作用域中间且其也有3个子作用域,像树一样被连在一起,好了printf要打印的i了,那i的定义在哪呢?首先在当前作用域里面找,没有,于是后序遍历往上在顶层作用域找到了,那这个i此时的值是啥呢?首先因为编译器是从上往下分析,这个i先是在main的作用域被赋值为9,在其子作用域有3个关于i的操作,第一个的i在当前作用域找不到定义,于是后续遍历找到顶层作用域那有个定义,于是这个i实际上与i=9那个i指向的是同一个内存地址(在.bss区,这个内存分布参考我第一篇博客),而剩下两个对i的定义抽像到汇编层次可能就是放在main函数堆栈的两个值,所以最后打印出来是2。(一个作用域一个符号表,编译器很有趣,后面也比较难,什么RTL之类的,好在有了lex等辅助生产工具,不过就算这样也很难,我认为和内核难度是一个层次的东西,我在这里面就简单写了一点无关紧要的东西,之后可能会有单独写编译器的文章)
好了铁轨铺好了,从编译器那产生个目标文件(gcc不是编译器,它是一个编译套件GNU Compiler Collection里面包含有编译器,汇编器,链接器),你可能要问为啥要有链接器和所谓目标文件,直接一步到位不是好,too naive,那些大型软件以及内核岂是区区一个或者几个文件能产生的,.o文件是一个c程序产生的目标文件,它是不能直接运行的,因为就像是铁轨要很多条联通才能运行一样,编译器只负责一个文件一个文件这样检查你的语法语义错误产生代码,你有没有相过万一我两个文件都在顶层作用域定义了个i那么可能只有鬼知道你指向的是哪个i的内存地址,于是搭铁轨的链接器诞生了,为了保持其目标文件的纯洁性独一性,往往目标代码是位置无关代码(很多编译器都有编译选项 -fplc就是确保如此,而且许多攻击setuid文件的漏洞都大致利用了此特性https://www.exploit-db.com/exploits/15274/),而且起始地址是0,于是重定位成了链接器的主要工作,就是把程序给映射到内存当中去,至于怎么个重定向法看之下的例子(我之前项目的一个小模块测试程序):
#include
#include
#include
#include
int fun(int a,...)
{}
int fun1;
int main()
{
int i= 0 ;
FILE *fp2,*fp1;
mkdir("/data", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
//fp1= fopen("/data/sequence.txt","wb");
fp2 = fopen("/data/sequence.txt","rb");
if (fp2 < 0)
perror("open");
//putw(i,fp2);
//fread(&i,sizeof(int),1,fp2);
i=getw(fp2);
printf("%d\n", i);
fclose(fp2);
fp1= fopen("/data/sequence.txt","wb");
putw(i,fp1);
fclose(fp1);
return 0;
}
这个程序的.o文件逆向出来是这样:
test4.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 :
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 48 sub $0x48,%rsp
8: 48 89 b5 58 ff ff ff mov %rsi,-0xa8(%rbp)
f: 48 89 95 60 ff ff ff mov %rdx,-0xa0(%rbp)
16: 48 89 8d 68 ff ff ff mov %rcx,-0x98(%rbp)
1d: 4c 89 85 70 ff ff ff mov %r8,-0x90(%rbp)
24: 4c 89 8d 78 ff ff ff mov %r9,-0x88(%rbp)
2b: 84 c0 test %al,%al
2d: 74 20 je 4f
2f: 0f 29 45 80 movaps %xmm0,-0x80(%rbp)
33: 0f 29 4d 90 movaps %xmm1,-0x70(%rbp)
37: 0f 29 55 a0 movaps %xmm2,-0x60(%rbp)
3b: 0f 29 5d b0 movaps %xmm3,-0x50(%rbp)
3f: 0f 29 65 c0 movaps %xmm4,-0x40(%rbp)
43: 0f 29 6d d0 movaps %xmm5,-0x30(%rbp)
47: 0f 29 75 e0 movaps %xmm6,-0x20(%rbp)
4b: 0f 29 7d f0 movaps %xmm7,-0x10(%rbp)
4f: 89 bd 4c ff ff ff mov %edi,-0xb4(%rbp)
55: c9 leaveq
56: c3 retq
0000000000000057 :
57: 55 push %rbp
58: 48 89 e5 mov %rsp,%rbp
5b: 48 83 ec 20 sub $0x20,%rsp
5f: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
66: be fd 01 00 00 mov $0x1fd,%esi
6b: bf 00 00 00 00 mov $0x0,%edi
70: e8 00 00 00 00 callq 75
75: be 00 00 00 00 mov $0x0,%esi
7a: bf 00 00 00 00 mov $0x0,%edi
7f: e8 00 00 00 00 callq 84
84: 48 89 45 f0 mov %rax,-0x10(%rbp)
88: 48 8b 45 f0 mov -0x10(%rbp),%rax
8c: 48 89 c7 mov %rax,%rdi
8f: e8 00 00 00 00 callq 94
94: 89 45 fc mov %eax,-0x4(%rbp)
97: 8b 45 fc mov -0x4(%rbp),%eax
9a: 89 c6 mov %eax,%esi
9c: bf 00 00 00 00 mov $0x0,%edi
a1: b8 00 00 00 00 mov $0x0,%eax
a6: e8 00 00 00 00 callq ab
ab: 48 8b 45 f0 mov -0x10(%rbp),%rax
af: 48 89 c7 mov %rax,%rdi
b2: e8 00 00 00 00 callq b7
b7: be 00 00 00 00 mov $0x0,%esi
bc: bf 00 00 00 00 mov $0x0,%edi
c1: e8 00 00 00 00 callq c6
c6: 48 89 45 e8 mov %rax,-0x18(%rbp)
ca: 48 8b 55 e8 mov -0x18(%rbp),%rdx
ce: 8b 45 fc mov -0x4(%rbp),%eax
d1: 48 89 d6 mov %rdx,%rsi
d4: 89 c7 mov %eax,%edi
d6: e8 00 00 00 00 callq db
db: 48 8b 45 e8 mov -0x18(%rbp),%rax
df: 48 89 c7 mov %rax,%rdi
e2: e8 00 00 00 00 callq e7
e7: b8 00 00 00 00 mov $0x0,%eax
ec: c9 leaveq
ed: c3 retq
Disassembly of section .rodata:
0000000000000000 <.rodata>:
0: 2f (bad)
1: 64 61 fs (bad)
3: 74 61 je 66
5: 00 72 62 add %dh,0x62(%rdx)
8: 00 2f add %ch,(%rdi)
a: 64 61 fs (bad)
c: 74 61 je 6f
e: 2f (bad)
f: 73 65 jae 76
11: 71 75 jno 88
13: 65 6e outsb %gs:(%rsi),(%dx)
15: 63 65 2e movslq 0x2e(%rbp),%esp
18: 74 78 je 92
1a: 74 00 je 1c <.rodata+0x1c>
1c: 25 64 0a 00 77 and $0x77000a64,%eax
21: 62 .byte 0x62
...
Disassembly of section .comment:
0000000000000000 <.comment>:
0: 00 47 43 add %al,0x43(%rdi)
3: 43 3a 20 rex.XB cmp (%r8),%spl
6: 28 44 65 62 sub %al,0x62(%rbp,%riz,2)
a: 69 61 6e 20 34 2e 39 imul $0x392e3420,0x6e(%rcx),%esp
11: 2e 32 2d 31 30 29 20 xor %cs:0x20293031(%rip),%ch # 20293049
18: 34 2e xor $0x2e,%al
1a: 39 2e cmp %ebp,(%rsi)
1c: 32 00 xor (%rax),%al
Disassembly of section .eh_frame:
0000000000000000 <.eh_frame>:
0: 14 00 adc $0x0,%al
2: 00 00 add %al,(%rax)
4: 00 00 add %al,(%rax)
6: 00 00 add %al,(%rax)
8: 01 7a 52 add %edi,0x52(%rdx)
b: 00 01 add %al,(%rcx)
d: 78 10 js 1f <.eh_frame+0x1f>
f: 01 1b add %ebx,(%rbx)
11: 0c 07 or $0x7,%al
13: 08 90 01 00 00 1c or %dl,0x1c000001(%rax)
19: 00 00 add %al,(%rax)
1b: 00 1c 00 add %bl,(%rax,%rax,1)
1e: 00 00 add %al,(%rax)
20: 00 00 add %al,(%rax)
22: 00 00 add %al,(%rax)
24: 57 push %rdi
25: 00 00 add %al,(%rax)
27: 00 00 add %al,(%rax)
29: 41 0e rex.B (bad)
2b: 10 86 02 43 0d 06 adc %al,0x60d4302(%rsi)
31: 02 52 0c add 0xc(%rdx),%dl
34: 07 (bad)
35: 08 00 or %al,(%rax)
37: 00 1c 00 add %bl,(%rax,%rax,1)
3a: 00 00 add %al,(%rax)
3c: 3c 00 cmp $0x0,%al
3e: 00 00 add %al,(%rax)
40: 00 00 add %al,(%rax)
42: 00 00 add %al,(%rax)
44: 97 xchg %eax,%edi
45: 00 00 add %al,(%rax)
47: 00 00 add %al,(%rax)
49: 41 0e rex.B (bad)
4b: 10 86 02 43 0d 06 adc %al,0x60d4302(%rsi)
51: 02 92 0c 07 08 00 add 0x8070c(%rdx),%dl
...
test4: file format elf64-x86-64
Disassembly of section .init:
00000000004004c0 <_init>:
4004c0: 48 83 ec 08 sub $0x8,%rsp
4004c4: 48 8b 05 7d 06 20 00 mov 0x20067d(%rip),%rax # 600b48 <_DYNAMIC+0x1d0>
4004cb: 48 85 c0 test %rax,%rax
4004ce: 74 05 je 4004d5 <_init+0x15>
4004d0: e8 6b 00 00 00 callq 400540 <__gmon_start__@plt>
4004d5: 48 83 c4 08 add $0x8,%rsp
4004d9: c3 retq
Disassembly of section .plt:
00000000004004e0 :
4004e0: ff 35 72 06 20 00 pushq 0x200672(%rip) # 600b58 <_GLOBAL_OFFSET_TABLE_+0x8>
4004e6: ff 25 74 06 20 00 jmpq *0x200674(%rip) # 600b60 <_GLOBAL_OFFSET_TABLE_+0x10>
4004ec: 0f 1f 40 00 nopl 0x0(%rax)
00000000004004f0 :
4004f0: ff 25 72 06 20 00 jmpq *0x200672(%rip) # 600b68 <_GLOBAL_OFFSET_TABLE_+0x18>
4004f6: 68 00 00 00 00 pushq $0x0
4004fb: e9 e0 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400500 :
400500: ff 25 6a 06 20 00 jmpq *0x20066a(%rip) # 600b70 <_GLOBAL_OFFSET_TABLE_+0x20>
400506: 68 01 00 00 00 pushq $0x1
40050b: e9 d0 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400510 :
400510: ff 25 62 06 20 00 jmpq *0x200662(%rip) # 600b78 <_GLOBAL_OFFSET_TABLE_+0x28>
400516: 68 02 00 00 00 pushq $0x2
40051b: e9 c0 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400520 :
400520: ff 25 5a 06 20 00 jmpq *0x20065a(%rip) # 600b80 <_GLOBAL_OFFSET_TABLE_+0x30>
400526: 68 03 00 00 00 pushq $0x3
40052b: e9 b0 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400530 <__libc_start_main@plt>:
400530: ff 25 52 06 20 00 jmpq *0x200652(%rip) # 600b88 <_GLOBAL_OFFSET_TABLE_+0x38>
400536: 68 04 00 00 00 pushq $0x4
40053b: e9 a0 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400540 <__gmon_start__@plt>:
400540: ff 25 4a 06 20 00 jmpq *0x20064a(%rip) # 600b90 <_GLOBAL_OFFSET_TABLE_+0x40>
400546: 68 05 00 00 00 pushq $0x5
40054b: e9 90 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400550 :
400550: ff 25 42 06 20 00 jmpq *0x200642(%rip) # 600b98 <_GLOBAL_OFFSET_TABLE_+0x48>
400556: 68 06 00 00 00 pushq $0x6
40055b: e9 80 ff ff ff jmpq 4004e0 <_init+0x20>
0000000000400560 :
400560: ff 25 3a 06 20 00 jmpq *0x20063a(%rip) # 600ba0 <_GLOBAL_OFFSET_TABLE_+0x50>
400566: 68 07 00 00 00 pushq $0x7
40056b: e9 70 ff ff ff jmpq 4004e0 <_init+0x20>
Disassembly of section .text:
0000000000400570 <_start>:
400570: 31 ed xor %ebp,%ebp
400572: 49 89 d1 mov %rdx,%r9
400575: 5e pop %rsi
400576: 48 89 e2 mov %rsp,%rdx
400579: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40057d: 50 push %rax
40057e: 54 push %rsp
40057f: 49 c7 c0 d0 07 40 00 mov $0x4007d0,%r8
400586: 48 c7 c1 60 07 40 00 mov $0x400760,%rcx
40058d: 48 c7 c7 bd 06 40 00 mov $0x4006bd,%rdi
400594: e8 97 ff ff ff callq 400530 <__libc_start_main@plt>
400599: f4 hlt
40059a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000004005a0 :
4005a0: b8 bf 0b 60 00 mov $0x600bbf,%eax
4005a5: 55 push %rbp
4005a6: 48 2d b8 0b 60 00 sub $0x600bb8,%rax
4005ac: 48 83 f8 0e cmp $0xe,%rax
4005b0: 48 89 e5 mov %rsp,%rbp
4005b3: 76 1b jbe 4005d0
4005b5: b8 00 00 00 00 mov $0x0,%eax
4005ba: 48 85 c0 test %rax,%rax
4005bd: 74 11 je 4005d0
4005bf: 5d pop %rbp
4005c0: bf b8 0b 60 00 mov $0x600bb8,%edi
4005c5: ff e0 jmpq *%rax
4005c7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
4005ce: 00 00
4005d0: 5d pop %rbp
4005d1: c3 retq
4005d2: 66 66 66 66 66 2e 0f data16 data16 data16 data16 nopw %cs:0x0(%rax,%rax,1)
4005d9: 1f 84 00 00 00 00 00
00000000004005e0 :
4005e0: be b8 0b 60 00 mov $0x600bb8,%esi
4005e5: 55 push %rbp
4005e6: 48 81 ee b8 0b 60 00 sub $0x600bb8,%rsi
4005ed: 48 c1 fe 03 sar $0x3,%rsi
4005f1: 48 89 e5 mov %rsp,%rbp
4005f4: 48 89 f0 mov %rsi,%rax
4005f7: 48 c1 e8 3f shr $0x3f,%rax
4005fb: 48 01 c6 add %rax,%rsi
4005fe: 48 d1 fe sar %rsi
400601: 74 15 je 400618
400603: b8 00 00 00 00 mov $0x0,%eax
400608: 48 85 c0 test %rax,%rax
40060b: 74 0b je 400618
40060d: 5d pop %rbp
40060e: bf b8 0b 60 00 mov $0x600bb8,%edi
400613: ff e0 jmpq *%rax
400615: 0f 1f 00 nopl (%rax)
400618: 5d pop %rbp
400619: c3 retq
40061a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000400620 <__do_global_dtors_aux>:
400620: 80 3d 91 05 20 00 00 cmpb $0x0,0x200591(%rip) # 600bb8 <__TMC_END__>
400627: 75 11 jne 40063a <__do_global_dtors_aux+0x1a>
400629: 55 push %rbp
40062a: 48 89 e5 mov %rsp,%rbp
40062d: e8 6e ff ff ff callq 4005a0
400632: 5d pop %rbp
400633: c6 05 7e 05 20 00 01 movb $0x1,0x20057e(%rip) # 600bb8 <__TMC_END__>
40063a: f3 c3 repz retq
40063c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400640 :
400640: bf 70 09 60 00 mov $0x600970,%edi
400645: 48 83 3f 00 cmpq $0x0,(%rdi)
400649: 75 05 jne 400650
40064b: eb 93 jmp 4005e0
40064d: 0f 1f 00 nopl (%rax)
400650: b8 00 00 00 00 mov $0x0,%eax
400655: 48 85 c0 test %rax,%rax
400658: 74 f1 je 40064b
40065a: 55 push %rbp
40065b: 48 89 e5 mov %rsp,%rbp
40065e: ff d0 callq *%rax
400660: 5d pop %rbp
400661: e9 7a ff ff ff jmpq 4005e0
0000000000400666 :
400666: 55 push %rbp
400667: 48 89 e5 mov %rsp,%rbp
40066a: 48 83 ec 48 sub $0x48,%rsp
40066e: 48 89 b5 58 ff ff ff mov %rsi,-0xa8(%rbp)
400675: 48 89 95 60 ff ff ff mov %rdx,-0xa0(%rbp)
40067c: 48 89 8d 68 ff ff ff mov %rcx,-0x98(%rbp)
400683: 4c 89 85 70 ff ff ff mov %r8,-0x90(%rbp)
40068a: 4c 89 8d 78 ff ff ff mov %r9,-0x88(%rbp)
400691: 84 c0 test %al,%al
400693: 74 20 je 4006b5
400695: 0f 29 45 80 movaps %xmm0,-0x80(%rbp)
400699: 0f 29 4d 90 movaps %xmm1,-0x70(%rbp)
40069d: 0f 29 55 a0 movaps %xmm2,-0x60(%rbp)
4006a1: 0f 29 5d b0 movaps %xmm3,-0x50(%rbp)
4006a5: 0f 29 65 c0 movaps %xmm4,-0x40(%rbp)
4006a9: 0f 29 6d d0 movaps %xmm5,-0x30(%rbp)
4006ad: 0f 29 75 e0 movaps %xmm6,-0x20(%rbp)
4006b1: 0f 29 7d f0 movaps %xmm7,-0x10(%rbp)
4006b5: 89 bd 4c ff ff ff mov %edi,-0xb4(%rbp)
4006bb: c9 leaveq
4006bc: c3 retq
00000000004006bd :
4006bd: 55 push %rbp
4006be: 48 89 e5 mov %rsp,%rbp
4006c1: 48 83 ec 20 sub $0x20,%rsp
4006c5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4006cc: be fd 01 00 00 mov $0x1fd,%esi
4006d1: bf e4 07 40 00 mov $0x4007e4,%edi
4006d6: e8 15 fe ff ff callq 4004f0
4006db: be ea 07 40 00 mov $0x4007ea,%esi
4006e0: bf ed 07 40 00 mov $0x4007ed,%edi
4006e5: e8 76 fe ff ff callq 400560
4006ea: 48 89 45 f0 mov %rax,-0x10(%rbp)
4006ee: 48 8b 45 f0 mov -0x10(%rbp),%rax
4006f2: 48 89 c7 mov %rax,%rdi
4006f5: e8 56 fe ff ff callq 400550
4006fa: 89 45 fc mov %eax,-0x4(%rbp)
4006fd: 8b 45 fc mov -0x4(%rbp),%eax
400700: 89 c6 mov %eax,%esi
400702: bf 00 08 40 00 mov $0x400800,%edi
400707: b8 00 00 00 00 mov $0x0,%eax
40070c: e8 ff fd ff ff callq 400510
400711: 48 8b 45 f0 mov -0x10(%rbp),%rax
400715: 48 89 c7 mov %rax,%rdi
400718: e8 e3 fd ff ff callq 400500
40071d: be 04 08 40 00 mov $0x400804,%esi
400722: bf ed 07 40 00 mov $0x4007ed,%edi
400727: e8 34 fe ff ff callq 400560
40072c: 48 89 45 e8 mov %rax,-0x18(%rbp)
400730: 48 8b 55 e8 mov -0x18(%rbp),%rdx
400734: 8b 45 fc mov -0x4(%rbp),%eax
400737: 48 89 d6 mov %rdx,%rsi
40073a: 89 c7 mov %eax,%edi
40073c: e8 df fd ff ff callq 400520
400741: 48 8b 45 e8 mov -0x18(%rbp),%rax
400745: 48 89 c7 mov %rax,%rdi
400748: e8 b3 fd ff ff callq 400500
40074d: b8 00 00 00 00 mov $0x0,%eax
400752: c9 leaveq
400753: c3 retq
400754: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40075b: 00 00 00
40075e: 66 90 xchg %ax,%ax
0000000000400760 <__libc_csu_init>:
400760: 41 57 push %r15
400762: 41 89 ff mov %edi,%r15d
400765: 41 56 push %r14
400767: 49 89 f6 mov %rsi,%r14
40076a: 41 55 push %r13
40076c: 49 89 d5 mov %rdx,%r13
40076f: 41 54 push %r12
400771: 4c 8d 25 e8 01 20 00 lea 0x2001e8(%rip),%r12 # 600960 <__frame_dummy_init_array_entry>
400778: 55 push %rbp
400779: 48 8d 2d e8 01 20 00 lea 0x2001e8(%rip),%rbp # 600968 <__init_array_end>
400780: 53 push %rbx
400781: 4c 29 e5 sub %r12,%rbp
400784: 31 db xor %ebx,%ebx
400786: 48 c1 fd 03 sar $0x3,%rbp
40078a: 48 83 ec 08 sub $0x8,%rsp
40078e: e8 2d fd ff ff callq 4004c0 <_init>
400793: 48 85 ed test %rbp,%rbp
400796: 74 1e je 4007b6 <__libc_csu_init+0x56>
400798: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40079f: 00
4007a0: 4c 89 ea mov %r13,%rdx
4007a3: 4c 89 f6 mov %r14,%rsi
4007a6: 44 89 ff mov %r15d,%edi
4007a9: 41 ff 14 dc callq *(%r12,%rbx,8)
4007ad: 48 83 c3 01 add $0x1,%rbx
4007b1: 48 39 eb cmp %rbp,%rbx
4007b4: 75 ea jne 4007a0 <__libc_csu_init+0x40>
4007b6: 48 83 c4 08 add $0x8,%rsp
4007ba: 5b pop %rbx
4007bb: 5d pop %rbp
4007bc: 41 5c pop %r12
4007be: 41 5d pop %r13
4007c0: 41 5e pop %r14
4007c2: 41 5f pop %r15
4007c4: c3 retq
4007c5: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1)
4007cc: 00 00 00 00
00000000004007d0 <__libc_csu_fini>:
4007d0: f3 c3 repz retq
Disassembly of section .fini:
00000000004007d4 <_fini>:
4007d4: 48 83 ec 08 sub $0x8,%rsp
4007d8: 48 83 c4 08 add $0x8,%rsp
4007dc: c3 retq
嘻嘻,你注意我打红色的那两句汇编语句,这就是重定向的一种方式,就是在.o文件中用相对地址,链接器会根据你标识符找到函数接口,在PLT(procedure linkage table)
找到相应函数地址给替换之前的标识符,是函数就在section .plt中找,每个外部定义的符号都在GOT中有对应条目,是函数则在PLT(哈哈,这就是好多ctf pwn题的一些基本,什么ROP攻击,ret2lib之类的都或多或少利用了可执行文件的这些接口泄露的真实lib函数地址用来跳到内核控制流来达到攻击目的)。用nm命令可以查看文件一些顶层作用域或者外部符号表:
0000000000600bb8 B __bss_start
0000000000600bb8 b completed.6661
0000000000600ba8 D __data_start
0000000000600ba8 W data_start
00000000004005a0 t deregister_tm_clones
0000000000400620 t __do_global_dtors_aux
0000000000600968 t __do_global_dtors_aux_fini_array_entry
0000000000600bb0 D __dso_handle
0000000000600978 d _DYNAMIC
0000000000600bb8 D _edata
0000000000600bc0 B _end
U fclose@@GLIBC_2.2.5
00000000004007d4 T _fini
U fopen@@GLIBC_2.2.5
0000000000400640 t frame_dummy
0000000000600960 t __frame_dummy_init_array_entry
0000000000400958 r __FRAME_END__
0000000000400666 T fun
0000000000600bbc B fun1
U getw@@GLIBC_2.2.5
0000000000600b50 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
00000000004004c0 T _init
0000000000600968 t __init_array_end
0000000000600960 t __init_array_start
00000000004007e0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600970 d __JCR_END__
0000000000600970 d __JCR_LIST__
w _Jv_RegisterClasses
00000000004007d0 T __libc_csu_fini
0000000000400760 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
00000000004006bd T main
U mkdir@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
U putw@@GLIBC_2.2.5
00000000004005e0 t register_tm_clones
0000000000400570 T _start
0000000000600bb8 D __TMC_END__
T代表在text区及代码区,B则是bss全局未初始化变量..etc。看红字部分代表这个符号表来自外部的库,连库版本都有,是不是很强大,这个只是一个目标文件链接成一个可执行代码的简单例子,多个目标文件链接时,链接器会将它们的.text,.data,.bss等等区合并,这时若你的目标文件里面有多个重复的标识符那么会链接失败,C语言在这点的就不如c++之类好,c语言的函数标识符(这个标识符是针对链接器来说,而不是在编译阶段的标识符)比较死,两个函数函数名相同但是参数不同在c里面算一个标识符,而c++的标识符会区分函数参数甚至连空间都有,于是有了 extern “c”这种修饰符用来统一编译和链接规则。搭铁轨说那么多就行了,更细节的在于汇编指令以及动态库之类的了,这也是和内核及操作系统有关的。下面是重中之重,就是内核控制流部分了。估计要写到第二篇。
众所周知,CPU通过读取rip(eip)寄存器的值给总线来控制底层硬件管脚的高低电平从而产生如此神奇的东西——计算机。所以你写的程序肯定一部分是给cpu控制流读取的(.text)而且必须还有一部分是用来存储上下文(也就是数据.bss.rodata.data..etc)的,这一部分映射到内存后(映射过程是由虚拟地址到线性地址最后才是物理地址,由于linux不采用分段机制,故线性地址和虚拟地址一样,一个32位地址大致分成这样:cr3(占10位,存页基址 )+页目录地址(10位)+页表地址(12位,这个是4kb页)64位可能就有多个页目录),给这部分内存起一个名就叫进程,且用一个叫task_struct的数据结构描述它,而其中常见信息存在thread_info这个字段里面(简称tts),且进程用fs_struct维护它打开的文件指针fd,这个参考我的第二篇博客,且用signal_struct这个维护接受信号(处理异常所必须),其实进程只是铺好的铁轨,至于上面有没有车在跑(cpu执行流),这个就和内核有关了,进程大致有7个状态,每个状态都对应一个双向链表(想深入了解看UTL),每一个进程都想抢cpu时间片也就是想schedule一下,不同版本的内核调度器不同,有的是O(1)调度,有的是CFS,有的是BNF,据我收集的资料CFS比较常见,因为其在上千个虚拟核并行的时候效果比较好,这个是O(1)调度的我认为算是形象的例子:http://www.manio.org/cn/scheduling-of-linux-view-of-society/,他描述的是大致没涉及到多核,内核还用了4个hash表标识进程,好让内核快速查找,比如说我们熟知的pid就是一个。进程之间的关系特别复杂,特别是在多核cpu的preempt竞争机制下,这里篇幅有限就不多说,我们假设每个cpu是一个司机,那么一个进程的结束就是在多个司机(也有可能是一个)的作用下cpu流把这个进程的.text走完(这个是正常结束,也有可能出现异常,比如说你ctrl+c时会向当前进程发一个SIGINT信号,若进程没有相应的信号处理函数则会被中断,可以参考这个http://blog.csdn.net/yikai2009/article/details/8643818),那么所谓多线程是啥呢?其实就是一个进程内有多个流,这个在用户态用pthread_create人为定义,它会把某个在当前进程空间的函数当做一个小车让cpu司机去驾驶,而且小车的轨道是铺好的,之下的就是多线程例子(取自我为上个项目编写的调试代码):
#include
#include
#include
#include
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static void pthread_func_1 (void);
static void pthread_func_2 (void);
int main (int argc, char** argv)
{
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
pthread_attr_t attr = {0};
int ret = 0;
pthread_attr_init (&attr);
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create (&pt_1, NULL, (void *)pthread_func_1, NULL);
if (ret != 0)
{
perror ("pthread_1_create");
}
ret = pthread_create (&pt_2, NULL,(void *) pthread_func_2, NULL);
if (ret != 0)
{
perror ("pthread_2_create");
}
pthread_join (pt_1, NULL);
pthread_join (pt_2, NULL);
return 0;
}
static void pthread_func_1 (void)
{
while (1)
{
int i = 0;
for (; i < 6; i++)
{
printf ("This is pthread_1.\n");
if (i==2)
{
pthread_cond_signal(&cond);
return 0;
}
}
}
}
static void pthread_func_2 (void)
{
while(1)
{
int rc;
pthread_mutex_lock(&mtx);
rc = pthread_cond_wait(&cond, &mtx);
if(rc ==0)
{
int i = 0;
for (; i < 3 ; i ++)
{
printf ("This is pthread_2.\n");
}
pthread_mutex_unlock(&mtx);
}
}
}
if((ret[0] = request_irq(61, axi_irq_handle1, IRQF_TRIGGER_RISING ,"axi_dev",NULL)) < 0)
{
printk(KERN_INFO "Request IRQ Failed with %d\n",ret[0]);
}
其中的参数61是管脚号,第二个参数是中断服务程序函数入口,第三个指定触发沿方式,第四个是驱动类名,最后一个一般为空。学过微机原理的同学们应该知道,很多芯片采用中断标志位用来判断中断类型,多核CPU用APIC来确定每一个中断信号能传到每个CPU,而intel采用了中断向量号来一一对应中断,(细节同见UTL)我在这举例就是想告诉你什么叫做内核流,内核流的轨道是像镀金一样高级轨道,当一个CPU司机开的进程车跑到这个地方就要小心了,很多恶意程序就是专门找你铺的轨道中这种地方利用各种手段达到劫车的地步,就是把你的内核CPU老司机劫持了, 控制它走向它想走的地方,好了限于时间,这篇到此结束,下一篇我有空我将继续升入CPU司机部分,调度,内核竞争之类的。