linux如何分析系统的堆栈,Linux内核分析:操作系统是如何工作的?

函数调用堆栈

堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间

堆栈的几个重要功能

函数调用框架

传递参数

保存返回地址

提供局部变量空间

等等

C语言编译器对堆栈的使用有一套的规则

了解堆栈存在的目的和编译器对堆栈使用的规则是理解操作系统一些关键性代码的基础

堆栈相关的寄存器

esp

ebp

相关操作

push 栈顶地址减少4个字节(32位)

pop 栈顶地址增加4个字节(32位)

32位模式下段寄存器出入栈都是用4个字节

ebp在C语言中用作记录当前函数调用的基址

其他关键寄存器

cs:eip 总是指向下一条的指令地址

call xxx

1. push cs:eip

2. 将xxx指向cs:eip

3. enter xxx

pushl %ebp

movl %esp, %ebp

do something

4. leave xxx

movl %ebp, %esp

popl %ebp

ret

一个例子

// test.c

#include

void p1(char c)

{

printf("%c\n", c);

}

int p2(int x, int y)

{

return x + y;

}

int main(void)

{

char c = 'a';

int x, y, z;

x = 1;

y = 2;

p1(c);

z = p2(x, y);

printf("%d=%d+%d\n", z, x, y);

}

编译

gcc -g -m32 -o test.o test.c

获得反汇编文件

objdump -S test.o

test.c完整的反汇编代码

test.o: 文件格式 elf32-i386

Disassembly of section .init:

080482b4 <_init>:

80482b4: 53 push %ebx

80482b5: 83 ec 08 sub $0x8,%esp

80482b8: e8 93 00 00 00 call 8048350 <__x86.get_pc_thunk.bx>

80482bd: 81 c3 43 1d 00 00 add $0x1d43,%ebx

80482c3: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax

80482c9: 85 c0 test %eax,%eax

80482cb: 74 05 je 80482d2 <_init>

80482cd: e8 2e 00 00 00 call 8048300 <__gmon_start__>

80482d2: 83 c4 08 add $0x8,%esp

80482d5: 5b pop %ebx

80482d6: c3 ret

Disassembly of section .plt:

080482e0 :

80482e0: ff 35 04 a0 04 08 pushl 0x804a004

80482e6: ff 25 08 a0 04 08 jmp *0x804a008

80482ec: 00 00 add %al,(%eax)

...

080482f0 :

80482f0: ff 25 0c a0 04 08 jmp *0x804a00c

80482f6: 68 00 00 00 00 push $0x0

80482fb: e9 e0 ff ff ff jmp 80482e0 <_init>

08048300 <__gmon_start__>:

8048300: ff 25 10 a0 04 08 jmp *0x804a010

8048306: 68 08 00 00 00 push $0x8

804830b: e9 d0 ff ff ff jmp 80482e0 <_init>

08048310 <__libc_start_main>:

8048310: ff 25 14 a0 04 08 jmp *0x804a014

8048316: 68 10 00 00 00 push $0x10

804831b: e9 c0 ff ff ff jmp 80482e0 <_init>

Disassembly of section .text:

08048320 <_start>:

8048320: 31 ed xor %ebp,%ebp

8048322: 5e pop %esi

8048323: 89 e1 mov %esp,%ecx

8048325: 83 e4 f0 and $0xfffffff0,%esp

8048328: 50 push %eax

8048329: 54 push %esp

804832a: 52 push %edx

804832b: 68 30 85 04 08 push $0x8048530

8048330: 68 c0 84 04 08 push $0x80484c0

8048335: 51 push %ecx

8048336: 56 push %esi

8048337: 68 4c 84 04 08 push $0x804844c

804833c: e8 cf ff ff ff call 8048310 <__libc_start_main>

8048341: f4 hlt

8048342: 66 90 xchg %ax,%ax

8048344: 66 90 xchg %ax,%ax

8048346: 66 90 xchg %ax,%ax

8048348: 66 90 xchg %ax,%ax

804834a: 66 90 xchg %ax,%ax

804834c: 66 90 xchg %ax,%ax

804834e: 66 90 xchg %ax,%ax

08048350 <__x86.get_pc_thunk.bx>:

8048350: 8b 1c 24 mov (%esp),%ebx

8048353: c3 ret

8048354: 66 90 xchg %ax,%ax

8048356: 66 90 xchg %ax,%ax

8048358: 66 90 xchg %ax,%ax

804835a: 66 90 xchg %ax,%ax

804835c: 66 90 xchg %ax,%ax

804835e: 66 90 xchg %ax,%ax

08048360 :

8048360: b8 23 a0 04 08 mov $0x804a023,%eax

8048365: 2d 20 a0 04 08 sub $0x804a020,%eax

804836a: 83 f8 06 cmp $0x6,%eax

804836d: 77 01 ja 8048370

804836f: c3 ret

8048370: b8 00 00 00 00 mov $0x0,%eax

8048375: 85 c0 test %eax,%eax

8048377: 74 f6 je 804836f

8048379: 55 push %ebp

804837a: 89 e5 mov %esp,%ebp

804837c: 83 ec 18 sub $0x18,%esp

804837f: c7 04 24 20 a0 04 08 movl $0x804a020,(%esp)

8048386: ff d0 call *%eax

8048388: c9 leave

8048389: c3 ret

804838a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi

08048390 :

8048390: b8 20 a0 04 08 mov $0x804a020,%eax

8048395: 2d 20 a0 04 08 sub $0x804a020,%eax

804839a: c1 f8 02 sar $0x2,%eax

804839d: 89 c2 mov %eax,%edx

804839f: c1 ea 1f shr $0x1f,%edx

80483a2: 01 d0 add %edx,%eax

80483a4: d1 f8 sar %eax

80483a6: 75 01 jne 80483a9

80483a8: c3 ret

80483a9: ba 00 00 00 00 mov $0x0,%edx

80483ae: 85 d2 test %edx,%edx

80483b0: 74 f6 je 80483a8

80483b2: 55 push %ebp

80483b3: 89 e5 mov %esp,%ebp

80483b5: 83 ec 18 sub $0x18,%esp

80483b8: 89 44 24 04 mov %eax,0x4(%esp)

80483bc: c7 04 24 20 a0 04 08 movl $0x804a020,(%esp)

80483c3: ff d2 call *%edx

80483c5: c9 leave

80483c6: c3 ret

80483c7: 89 f6 mov %esi,%esi

80483c9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi

080483d0 <__do_global_dtors_aux>:

80483d0: 80 3d 20 a0 04 08 00 cmpb $0x0,0x804a020

80483d7: 75 13 jne 80483ec <__do_global_dtors_aux>

80483d9: 55 push %ebp

80483da: 89 e5 mov %esp,%ebp

80483dc: 83 ec 08 sub $0x8,%esp

80483df: e8 7c ff ff ff call 8048360

80483e4: c6 05 20 a0 04 08 01 movb $0x1,0x804a020

80483eb: c9 leave

80483ec: f3 c3 repz ret

80483ee: 66 90 xchg %ax,%ax

080483f0 :

80483f0: a1 10 9f 04 08 mov 0x8049f10,%eax

80483f5: 85 c0 test %eax,%eax

80483f7: 74 1f je 8048418

80483f9: b8 00 00 00 00 mov $0x0,%eax

80483fe: 85 c0 test %eax,%eax

8048400: 74 16 je 8048418

8048402: 55 push %ebp

8048403: 89 e5 mov %esp,%ebp

8048405: 83 ec 18 sub $0x18,%esp

8048408: c7 04 24 10 9f 04 08 movl $0x8049f10,(%esp)

804840f: ff d0 call *%eax

8048411: c9 leave

8048412: e9 79 ff ff ff jmp 8048390

8048417: 90 nop

8048418: e9 73 ff ff ff jmp 8048390

0804841d :

#include

void p1(char c)

{

804841d: 55 push %ebp

804841e: 89 e5 mov %esp,%ebp

8048420: 83 ec 18 sub $0x18,%esp

8048423: 8b 45 08 mov 0x8(%ebp),%eax

8048426: 88 45 f4 mov %al,-0xc(%ebp)

printf("%c\n", c);

8048429: 0f be 45 f4 movsbl -0xc(%ebp),%eax

804842d: 89 44 24 04 mov %eax,0x4(%esp)

8048431: c7 04 24 50 85 04 08 movl $0x8048550,(%esp)

8048438: e8 b3 fe ff ff call 80482f0

}

804843d: c9 leave

804843e: c3 ret

0804843f :

int p2(int x, int y)

{

804843f: 55 push %ebp

8048440: 89 e5 mov %esp,%ebp

return x + y;

8048442: 8b 45 0c mov 0xc(%ebp),%eax

8048445: 8b 55 08 mov 0x8(%ebp),%edx

8048448: 01 d0 add %edx,%eax

}

804844a: 5d pop %ebp

804844b: c3 ret

0804844c :

int main(void)

{

804844c: 55 push %ebp

804844d: 89 e5 mov %esp,%ebp

804844f: 83 e4 f0 and $0xfffffff0,%esp

8048452: 83 ec 20 sub $0x20,%esp

char c = 'a';

8048455: c6 44 24 13 61 movb $0x61,0x13(%esp)

int x, y, z;

x = 1;

804845a: c7 44 24 14 01 00 00 movl $0x1,0x14(%esp)

8048461: 00

y = 2;

8048462: c7 44 24 18 02 00 00 movl $0x2,0x18(%esp)

8048469: 00

p1(c);

804846a: 0f be 44 24 13 movsbl 0x13(%esp),%eax

804846f: 89 04 24 mov %eax,(%esp)

8048472: e8 a6 ff ff ff call 804841d

z = p2(x, y);

8048477: 8b 44 24 18 mov 0x18(%esp),%eax

804847b: 89 44 24 04 mov %eax,0x4(%esp)

804847f: 8b 44 24 14 mov 0x14(%esp),%eax

8048483: 89 04 24 mov %eax,(%esp)

8048486: e8 b4 ff ff ff call 804843f

804848b: 89 44 24 1c mov %eax,0x1c(%esp)

printf("%d=%d+%d\n", z, x, y);

804848f: 8b 44 24 18 mov 0x18(%esp),%eax

8048493: 89 44 24 0c mov %eax,0xc(%esp)

8048497: 8b 44 24 14 mov 0x14(%esp),%eax

804849b: 89 44 24 08 mov %eax,0x8(%esp)

804849f: 8b 44 24 1c mov 0x1c(%esp),%eax

80484a3: 89 44 24 04 mov %eax,0x4(%esp)

80484a7: c7 04 24 54 85 04 08 movl $0x8048554,(%esp)

80484ae: e8 3d fe ff ff call 80482f0

}

80484b3: c9 leave

80484b4: c3 ret

80484b5: 66 90 xchg %ax,%ax

80484b7: 66 90 xchg %ax,%ax

80484b9: 66 90 xchg %ax,%ax

80484bb: 66 90 xchg %ax,%ax

80484bd: 66 90 xchg %ax,%ax

80484bf: 90 nop

080484c0 <__libc_csu_init>:

80484c0: 55 push %ebp

80484c1: 57 push %edi

80484c2: 31 ff xor %edi,%edi

80484c4: 56 push %esi

80484c5: 53 push %ebx

80484c6: e8 85 fe ff ff call 8048350 <__x86.get_pc_thunk.bx>

80484cb: 81 c3 35 1b 00 00 add $0x1b35,%ebx

80484d1: 83 ec 1c sub $0x1c,%esp

80484d4: 8b 6c 24 30 mov 0x30(%esp),%ebp

80484d8: 8d b3 0c ff ff ff lea -0xf4(%ebx),%esi

80484de: e8 d1 fd ff ff call 80482b4 <_init>

80484e3: 8d 83 08 ff ff ff lea -0xf8(%ebx),%eax

80484e9: 29 c6 sub %eax,%esi

80484eb: c1 fe 02 sar $0x2,%esi

80484ee: 85 f6 test %esi,%esi

80484f0: 74 27 je 8048519 <__libc_csu_init>

80484f2: 8d b6 00 00 00 00 lea 0x0(%esi),%esi

80484f8: 8b 44 24 38 mov 0x38(%esp),%eax

80484fc: 89 2c 24 mov %ebp,(%esp)

80484ff: 89 44 24 08 mov %eax,0x8(%esp)

8048503: 8b 44 24 34 mov 0x34(%esp),%eax

8048507: 89 44 24 04 mov %eax,0x4(%esp)

804850b: ff 94 bb 08 ff ff ff call *-0xf8(%ebx,%edi,4)

8048512: 83 c7 01 add $0x1,%edi

8048515: 39 f7 cmp %esi,%edi

8048517: 75 df jne 80484f8 <__libc_csu_init>

8048519: 83 c4 1c add $0x1c,%esp

804851c: 5b pop %ebx

804851d: 5e pop %esi

804851e: 5f pop %edi

804851f: 5d pop %ebp

8048520: c3 ret

8048521: eb 0d jmp 8048530 <__libc_csu_fini>

8048523: 90 nop

8048524: 90 nop

8048525: 90 nop

8048526: 90 nop

8048527: 90 nop

8048528: 90 nop

8048529: 90 nop

804852a: 90 nop

804852b: 90 nop

804852c: 90 nop

804852d: 90 nop

804852e: 90 nop

804852f: 90 nop

08048530 <__libc_csu_fini>:

8048530: f3 c3 repz ret

Disassembly of section .fini:

08048534 <_fini>:

8048534: 53 push %ebx

8048535: 83 ec 08 sub $0x8,%esp

8048538: e8 13 fe ff ff call 8048350 <__x86.get_pc_thunk.bx>

804853d: 81 c3 c3 1a 00 00 add $0x1ac3,%ebx

8048543: 83 c4 08 add $0x8,%esp

8048546: 5b pop %ebx

8048547: c3 ret

C代码嵌入汇编代码

内嵌汇编语法

__asm__(

汇编语句模板:

输出部分:

输入部分:

破坏描述部分

);

即格式为 asm("statements":output_regs:input_regs:clobbered_regs);

asm是__asm__的别名

volatile是__volatile__的别名,表示编译器不要优化代码

asm.c

// asm.c

#include

int main()

{

/*val1+val2=val3*/

unsigned int val1 = 1;

unsigned int val2 = 2;

unsigned int val3 = 0;

printf("val1:%d,val2:%d,val3:%d\n",val1,val2,val3);

asm volatile(

"movl $0,%%eax\n\t" /*clear %eax to 0*/

"addl %1,%%eax\n\t" /*%eax += val1*/

"addl %2,%%eax\n\t" /*%eax += val2*/

"movl %%eax,%0\n\t" /*val2 = %eax*/

: "=m" (val3) /* output =m mean only write output memory variable*/

: "c" (val1),"d" (val2) /*input c or d mean %ecx/%edx*/

);

printf("val1:%d+val2:%d=val3:%d\n",val1,val2,val3);

return 0;

}

内嵌汇编常用限定符

7ad34de6dd8b?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

c_asm.png

asm2.c

int main(void)

{

int input, output, temp;

input = 1;

__asm__ __volatile__(

"movl $0, %%eax;\n\t"

"movl %%eax, %1;\n\t"

"movl %2, %%eax;\n\t"

"movl %%eax, %0;\n\t"

: "=m"(output), "=m"(temp)

: "r"(input)

: "eax"

);

printf("%d %d\n", temp, output);

return 0;

}

// %0代表output, %1代表temp, %2代表input

如果工程很大,头文件很多,而有几个头文件又经常要用的,那么: 1、把这些头文件全部写到一个头文件中,比如:preh.h 2、写一个preh.c,里面的包含库文件,只要一句话#include"preh.h" 3、对于preh.c,在project settings 里面设置creat precompilesd headers ,对于其他.c文件,设置use precompiled header file 。 预编译头文件:就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以.pch为扩展名的),这个文件就成为预编译头文件。这些预先编译好的代码可以是任何的C/C++代码,甚至是inline的函数,但必须是稳定的在工程开发的过程中不会被经常改变。 编译器是以文件为单位编译的,一个文件经过修改后,会重新编译整个文件,当然在这个文件里包含的所有头文件中的东西都要重新处理一遍 预编译头的作用: 根据上文介绍,预编译头文件的作用当然就是提高便宜速度了,有了它你没有必要每次 都编译那些不需要经常改变的代码。编译性能当然就提高了。 预编译头的使用: 要使用预编译头,我们必须指定一个头文件,这个头文件包含我们不会经常改变的 代码和其他的头文件,然后我们用这个头文件来生成一个预编译头文件(.pch文件) 想必大家都知道 StdAfx.h这个文件。很多人都认为这是VC提供的一个“系统级别”的 ,编译器带的一个头文件。其实不是的,这个文件可以是任何名字的。我们来考察一个 典型的由AppWizard生成的MFC Dialog Based 程序的预编译头文件。(因为AppWizard 会为我们指定好如何使用预编译头文件,默认的是StdAfx.h,这是VC起的名字)。我们 会发现这个头文件里包含了以下的头文件: #include // MFC core and standard components #include // MFC extensions #include // MFC Automation classes #include // MFC support for Internet Explorer 4 Common Controls #include 这些正是使用MFC的必须包含的头文件,当然我们不太可能在我们的工程中修改这些头文 件的,所以说他们是稳定的。 那么我们如何指定它来生成预编译头文件。我们知道一个头文件是不能编译的。所以我 们还需要一个cpp文件来生成.pch 文件。这个文件默认的就是StdAfx.cpp。在这个文件 里只有一句代码就是:#include “Stdafx.h”。原因是理所当然的,我们仅仅是要它能 够编译而已?D?D?D也就是说,要的只是它的.cpp的扩展名。 我们可以用/Yc编译开关来指 定StdAfx.cpp来生成一个.pch文件,通过/Fp编译开关来指定生成的pch文件的名字。打 开project ->Setting->C/C++ 对话框。把Category指向Precompiled Header。在左边的 树形视图里选择整个工程  Project Options(右下角的那个白的地方)可以看到 /Fp “debug/PCH.pch”,这就是指 定生成的.pch文件的名字,默认的通常是 .pch(我的示例工程名就是PCH)。 然后,在左边的树形视图里选择StdAfx.cpp.//这时只能选一个cpp文件! 这时原来的Project Option变成了 Source File Option(原来是工程,现在是一个文件 ,当然变了)。在这里我们可以看到 /Yc开关,/Yc的作用就是指定这个文件来创建一个 Pch文件。/Yc后面的文件名是那个包含了稳定代码的头文件,一个工程里只能有一个文 件的可以有YC开关。VC就根据这个选项把 StdAfx.cpp编译成一个Obj文件和一个PCH文件 。 然后我们再选择一个其它的文件来看看,//其他cpp文件 在这里,Precomplier 选择了 Use ⋯⋯⋯一项,头文件是我们指定创建PCH 文件的stda fx.h 文件。事实上,这里是使用工程里的设置,(如图1)/Yu”stdafx.h”。 这样,我们就设置好了预编译头文件。也就是说,我们可以使用预编译头功能了。以 下是注意事项: 1):如果使用了/Yu,就是说使用了预编译,我们在每个.cpp文件的最开头,我强调一遍 是最开头,包含 你指定产生pch文件的.h文件(默认是stdafx.h)不然就会有问题。如 果你没有包含这个文件,就告诉你Unexpected file end. 如果你不是在最开头包含的, 你自己试以下就知道了,绝对有很惊人的效果⋯.. fatal error C1010: unexp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值