函数调用堆栈
堆栈是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 <stdio.h>
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+0x1e>
80482cd: e8 2e 00 00 00 call 8048300 <__gmon_start__@plt>
80482d2: 83 c4 08 add $0x8,%esp
80482d5: 5b pop %ebx
80482d6: c3 ret
Disassembly of section .plt:
080482e0 <printf@plt-0x10>:
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 <printf@plt>:
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+0x2c>
08048300 <__gmon_start__@plt>:
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+0x2c>
08048310 <__libc_start_main@plt>:
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+0x2c>
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@plt>
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 <deregister_tm_clones>:
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 <deregister_tm_clones+0x10>
804836f: c3 ret
8048370: b8 00 00 00 00 mov $0x0,%eax
8048375: 85 c0 test %eax,%eax
8048377: 74 f6 je 804836f <deregister_tm_clones+0xf>
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 <register_tm_clones>:
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 <register_tm_clones+0x19>
80483a8: c3 ret
80483a9: ba 00 00 00 00 mov $0x0,%edx
80483ae: 85 d2 test %edx,%edx
80483b0: 74 f6 je 80483a8 <register_tm_clones+0x18>
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+0x1c>
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 <deregister_tm_clones>
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 <frame_dummy>:
80483f0: a1 10 9f 04 08 mov 0x8049f10,%eax
80483f5: 85 c0 test %eax,%eax
80483f7: 74 1f je 8048418 <frame_dummy+0x28>
80483f9: b8 00 00 00 00 mov $0x0,%eax
80483fe: 85 c0 test %eax,%eax
8048400: 74 16 je 8048418 <frame_dummy+0x28>
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 <register_tm_clones>
8048417: 90 nop
8048418: e9 73 ff ff ff jmp 8048390 <register_tm_clones>
0804841d <p1>:
#include <stdio.h>
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 <printf@plt>
}
804843d: c9 leave
804843e: c3 ret
0804843f <p2>:
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 <main>:
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 <p1>
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 <p2>
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 <printf@plt>
}
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+0x59>
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+0x38>
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 <stdio.h>
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;
}
内嵌汇编常用限定符
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