Lesson06 PoEdu培训第一课 计算机科学篇(6) 汇编和可执行文件
文章类别: 培训笔记 0 评论

Lesson06 PoEdu培训第一课 计算机科学篇(6) 汇编和可执行文件

文章类别: 培训笔记 0 评论

汇编和可执行文件

    汇编 ≈ 机器码

如何生成一个可执行文件

    生成可执行文件需要进行两步操作.
    1. 编译
    2. 链接

编译

    源代码 ---> 编译器进行编译 ---> 汇编代码

编译的过程, 就是 按照代码规则, 生成与之一一对应的汇编代码 出来.

    1. 汇编码是不可执行的
    2. 在编译器执行完成后, 会生成.obj后缀名的文件, 
       里边就是存放的与代码一一对应的汇编码

链接

    链接器会将编译出来的obj文件进行链接操作, 生成可执行文件.

链接器的作用

    链接器的作用就是告诉操作系统, 我需要用你的哪些API, 然后建立与操作系统的链接.

在Windows平台下, 链接器的工作, 其实就是将编译后的obj进行深加工, 变成PE结构.

编译器

    编译器会自己进行代码优化
    如果程序源代码中有无用代码, 那么编译器在进行编译的时候, 有可能会优化掉.

在编译的时候, 可能会生成不一样的代码.

比如代码优化

比如调试版, 发布版等配置.

    在调试程序的时候, 建议使用Debug版, 也就是调试版.
    因为调试版会对你的没一句代码都生成相应的汇编码, 会完全编译, 不会被省略.

编译器的本质, 其实就是将一些复杂逻辑分解成一些简单逻辑.

汇编代码

汇编代码的分类

    赋值语句  
        比如: mov [目标] [源]
            移动执行, 将"源"的值移动到"目标"中.
    跳转语句
        比如: jmp [地址]
            最暴力的跳转指令!
    计算语句
        比如: add eax, ebx
            两者相加, 不解释.

这里仅仅举个例子, 汇编指令还是很多的.

有兴趣的可以: 扩展阅读

可执行程序的运行

    程序都是运行在物理内存中的.

内存分配

程序加载的时候, 内存会分成几块

代码

常量

为什么这样分?

    因为它更加安全.
    
    从CPU或者内存角度来看, 这些内存其实都是一样的.
    如果一种可以操作内存的语言(如:C/C++), 我们在利用它编写程序的时候,
    一不小心, 或者有意而为的, 将指针指向到了代码区, 并且很不小心或者很用心的修改了
    要是改的不好, 那么程序就挂掉了~

    在进行内存的分区之后, 我们可以采取一些保护措施.
    比如, 将代码和常量两块内存设置为只读的内存.
    就算在指向过来, 也没有用, 也不会被修改.

    在程序开始运行的时候, 默认生成1024KB大小的一块内存.
    这块内存, 我们称之为 栈.

扩展:

编程的时候可能会碰到栈溢出.

比如如下代码:

int main ()
{
    char strBuffer[1024 * 1024] = { 0 };
    return 0;
}

亲自运行一下, 就会出现异常:

Alt 异常图片

Alt 异常图片

那我们如何解决呢?

答案: 放到堆上.

代码写成如下方式:

int main ()
{
    char *strBuffer = new char[1024 * 1024];
    delete strBuffer;
    return 0;
}

栈中存储的是什么?

临时变量

跳转后的返回地址

传递的参数

为什么临时变量放到栈上

    因为临时变量是需要占用空间的.
    如果每次分配后在进行释放, 是需要浪费时间的.

    放到栈上是怎么简单实现释放的呢?
    首先, EBP寄存器存储栈底. 
    每当有临时变量过来, 就PUSH入栈, 分配空间.
    这时候, 我们使用另一个寄存器ESP来保存目前已使用的栈的栈顶

    当我们函数调用完成, 或者我们临时变量使用完成后, 
    只需要简单的执行  mov esp, ebp 这条指令.
    也就是说, 将栈顶重置回栈底, 这样, 栈底之上的数据都不会被访问到了.临时变量就相当于被释放了.
    如果来了新的临时变量, 那么重新分配地址即可.

所以, 栈是能反复使用的.

函数调用过程中, 为什么EBP(栈底)会变化?

    通常, 我们将ESP--EBP之间, 称为一个函数的栈.
    当使用 Call 指令进行 函数调用 的时候, 
    我们需要对当前运行程序的一个小的上下文进行保存.
    原理同CPU中断保存上下文

栈的操作

    PUSH    入栈, 压栈 
    POP     出栈

常用寄存器

    EIP 程序计数器  
    EFL 标志寄存器  
    EAX 累加寄存器  
    EDI 源寄存器  
    ESI 基址寄存器
    EBP 栈底  
    ESP 栈顶

寄存器扩展阅读

想了解更多? 请 点我阅读

如有错误,请提出指正!谢谢.

回复