计算机之旅(just for fun)(未完)

 未经允许,拒绝转载

  这篇文章综合了目前我在编译原理,linux内核,以及其它涉及计算机方面的认识。推荐书籍:UTL(深入理解linux内核),龙书,linkers and loaders,以及一个国产的编译原理透视,csapp也行不过感觉在内核方面不怎么深入。我将尽可能不过多深入细节,因为一旦深入细节估计我几十篇博客都说不完,我只对整个框架作探讨。

      在你编程的时候你有考虑过你写的东西在计算机上是怎么布置和运行的吗?我可以用一组形象的比喻来帮助你了解整个程序运行的计算机各个方面的参与,看完过后希望你可以像我一样对整个计算机软件架构组成感到不可思议以及那深深地敬仰。

     从你编写的程序(你所输入的是ASII码)到计算机能识别的目标文件是编译器的事,而后链接器把多个目标文件及.o文件以及一些动态库给链接成一个能在内核里面执行的可执行文件。形象的比喻是你就像是一个铁路铁轨的规划师,编译器负责按照你的规划造铁轨,造完后链接器把它装上去,内核的控制流才能控制CPU及火车在你的铁路上跑(我这控制流的比喻是有深意的,稍后看完就知道),对于c语言这种结构化的语言(在我看来是面向内存的语言微笑)来说,结构是核心,及“{}”这个是核心,在这用代码举个例子:

#include <stdio.h>
#include <stdlib.h>
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;
}

你猜猜打印是啥,如果你能第一时间答对,你对C编译器的语法分析的一个大特性算是了解了。(编译器 mingw32-gcc)

让我来解释解释,所有数据都用一个标识符表示,在词法分析时会生成一个token也及一个词法单元每个词法单元都会有一些可选的属性值,词法分析是怎么分析的呢,用的是有穷自动机算法来做状态机(每种类型比如说 空白键,无符号数字都是一个状态转移图,有穷自动机就是匹配这些状态的一种算法),有穷自动机算法会匹配各个词素而词素(也就是有意义的字符串)就是词法单元的一个实例,比如说

int i
词法分析编译器扫到i这个字母时会往下继续一直遇到分隔符(空格换行符这些),得到int这个字符串(其中还有一些加快分析的方法比如说用缓冲区对),恰好是个保留字(keyword,系统预定义在GCC一个函数里面有,因为函数名比较长我忘记了 微笑不过我为啥知道用L在字符串之前也是看gcc源代码知道的)于是这个词素的类型就是CST__INT(反正是系统预定义的),而后遇到i,这个不是特殊保留字于是把它当作标识符并生成类似于<id,1>这样的词法单元,id为该标识符的抽象符号(相当于一个指向该标识符的指针,1为指向符号表的指针),标识符类型在语法分析的时候确定就是int,于是标识符i有了一些属性,前面说到的符号表的使用其实是在语义分析中由语法制导翻译(syntax-directed translation)阶段才用到,在遇到“{”时相当于进入了个新作用域,此时编译器会更新当前作用域已经相应的符号表。是不是看到现在有些昏。。因为实际上更复杂(具体感兴趣可以看龙书),总之作用域是每个语言非常关键的地方,C语言的作用域是人为规划的,所以很多人不了解原理会乱用,作用域的环境在C中是一棵树形结构,采用后续遍历,和最近嵌套规则(most-closely), 这就是为啥最后打印结果为2的原因

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 <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
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 <fun>:
   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 <fun+0x4f>
  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 <main>:
  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 <main+0x1e>
  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 <main+0x2d>
  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 <main+0x3d>
  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 <main+0x54>
  ab:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
  af:	48 89 c7             	mov    %rax,%rdi
  b2:	e8 00 00 00 00       	callq  b7 <main+0x60>
  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 <main+0x6f>
  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 <main+0x84>
  db:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  df:	48 89 c7             	mov    %rax,%rdi
  e2:	e8 00 00 00 00       	callq  e7 <main+0x90>
  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 <main+0xf>
   5:	00 72 62             	add    %dh,0x62(%rdx)
   8:	00 2f                	add    %ch,(%rdi)
   a:	64 61                	fs (bad) 
   c:	74 61                	je     6f <main+0x18>
   e:	2f                   	(bad)  
   f:	73 65                	jae    76 <main+0x1f>
  11:	71 75                	jno    88 <main+0x31>
  13:	65 6e                	outsb  %gs:(%rsi),(%dx)
  15:	63 65 2e             	movslq 0x2e(%rbp),%esp
  18:	74 78                	je     92 <main+0x3b>
  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 <main+0x20292ff2>
  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
	...

AT&T的汇编格式 至于你想改成其它啥格式逆向你可以参考我的第一篇博客,再看看反汇编可执行程序的样子:(我已把一些表示版本号和其它的辅助性区给人为去掉或者你用objdump -S命令):
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 <mkdir@plt-0x10>:
  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 <mkdir@plt>:
  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 <fclose@plt>:
  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 <printf@plt>:
  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 <putw@plt>:
  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 <getw@plt>:
  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 <fopen@plt>:
  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 <deregister_tm_clones>:
  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 <deregister_tm_clones+0x30>
  4005b5:	b8 00 00 00 00       	mov    $0x0,%eax
  4005ba:	48 85 c0             	test   %rax,%rax
  4005bd:	74 11                	je     4005d0 <deregister_tm_clones+0x30>
  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 <register_tm_clones>:
  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 <register_tm_clones+0x38>
  400603:	b8 00 00 00 00       	mov    $0x0,%eax
  400608:	48 85 c0             	test   %rax,%rax
  40060b:	74 0b                	je     400618 <register_tm_clones+0x38>
  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 <deregister_tm_clones>
  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 <frame_dummy>:
  400640:	bf 70 09 60 00       	mov    $0x600970,%edi
  400645:	48 83 3f 00          	cmpq   $0x0,(%rdi)
  400649:	75 05                	jne    400650 <frame_dummy+0x10>
  40064b:	eb 93                	jmp    4005e0 <register_tm_clones>
  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 <frame_dummy+0xb>
  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 <register_tm_clones>

0000000000400666 <fun>:
  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 <fun+0x4f>
  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 <main>:
  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 <mkdir@plt>
  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 <fopen@plt>
  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 <getw@plt>
  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 <printf@plt>
  400711:	48 8b 45 f0          	mov    -0x10(%rbp),%rax
  400715:	48 89 c7             	mov    %rax,%rdi
  400718:	e8 e3 fd ff ff       	callq  400500 <fclose@plt>
  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 <fopen@plt>
  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 <putw@plt>
  400741:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  400745:	48 89 c7             	mov    %rax,%rdi
  400748:	e8 b3 fd ff ff       	callq  400500 <fclose@plt>
  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 <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
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);  
  		} 
	}
}

中间的那个互斥锁和条件信号限于篇幅我不讲了(可能下一篇会说), ,你会发现所谓多线程就是如此,而内核态多线程复杂得多,因为内核时刻都在运行,内核态的进程必须自己释放CPU,而有个特殊的内核执行流要深入研究,那就是中断,一个进程遇到中断时CPU会直接跳到内核态去运行相应的中断服务程序,这中间不像进程切换要调用switch_to保存诸如页基址,堆栈之类的,只用保存少量上下文(eip,cs之类的计数器),而在内核模块定义中断是这样定义的, 中断的输入是硬件管脚,这是无规律且很必然事件,所以很多时候CPU必须优先处理(这个是我上一个驱动项目代码的一部分):
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司机部分,调度,内核竞争之类的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值