技术向程序员IT共论

How Does a Computer Work?

2016-02-26  本文已影响179人  AMG架构师

《Linux 内核分析》 MOOC 课程实验 通过反汇编一段简单的 C 程序,分析汇编代码,理解计算机的工作原理。

1.计算机体系结构

计算机诞生距今正好 60 年的历史,尽管如今的计算机在性能指标、运算速度、应用领域等方面与过去有了天翻地覆的差别,但是基本的体系结构却一直没有变过,也就是大家常说的冯·诺依曼体系结构

冯·诺依曼开创性的提出了"存储程序"的概念,把指令和数据同时存放在存储器中,奠定了现代计算机的结构理论。


概括来说,主要有如下三点:

2.反汇编分析一段 C 语言程序的执行

int g(int x)
{
    return x + 9;
}
     
int f(int x)
{
    return g(x);
}
     
int main(void)
{
    return f(8) + 6;
}

通过实验楼的已搭建好的 64 位 Linux 虚拟机环境,反汇编上述 C 代码:

gcc -S -o main.s main.c -m32

汇编代码:

    .file   "main.c"
    .text
    .globl  g
    .type   g, @function
g:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    8(%ebp), %eax
    addl    $9, %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size   g, .-g
    .globl  f
    .type   f, @function
f:
.LFB1:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $4, %esp
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    g
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE1:
    .size   f, .-f
    .globl  main
    .type   main, @function
main:
.LFB2:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $4, %esp
    movl    $8, (%esp)
    call    f
    addl    $6, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE2:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

汇编代码分析:

首先从 main 函数开始,前两条语句:

pushl   %ebp
movl    %esp, %ebp

出现在所有函数的开头,表示将基指针压进栈,然后把栈顶指针的值赋给基指针。

subl    $4, %esp
movl    $8, (%esp)

然后,由于栈是由高地址向低地址扩展,在 32 位操作系统系统上,每个栈元素为 4 个字节,所以栈顶指针减 4,同时,采用立即数寻址的方式,把局部变量 8 放入栈顶指针所指向的位置。call 指令调用函数 f 执行,在这里 call 首先保存当前 %eip 的值,然后读取待执行函数 f 的指令地址:

call f

函数 f 以同样的形式进栈并继续调用函数 g,把局部变量 9 保存在 Accumulator Register eax 中,然后 popl 出栈返回到先前函数 f 中 call 指令保存执行指令地址:

addl    $9, %eax
popl    %ebp

函数 f 的 leave 指令相当于:

movl  %ebp, %esp
popl  %ebp

返回到 main 函数中继续执行直至函数运行结束,在此不再赘述。

addl    $6, %eax
leave

3.总结:

冯·诺依曼体系告诉我们,程序数据和指令被计算机以二进制的形式不加区分的存储在存储器中,理解了"存储程序",然后再去理解计算机的执行过程就变得非常容易了。
上一篇下一篇

猜你喜欢

热点阅读