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

函数调用堆栈

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

堆栈的几个重要功能

  1. 函数调用框架
  2. 传递参数
  3. 保存返回地址
  4. 提供局部变量空间
  5. 等等

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+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 :
 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+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 :
 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+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 
 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+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 
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;
}

内嵌汇编常用限定符

Linux内核分析:操作系统是如何工作的?_第1张图片
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

你可能感兴趣的:(Linux内核分析:操作系统是如何工作的?)