zoukankan      html  css  js  c++  java
  • 《程序是怎样跑起来的》读书笔记——第十章 通过汇编语言了解程序的实际构成

    1 汇编语言和本地代码是一一对应的

    • 1⃣️计算机 CPU 能直接解释运行的只有本地代码(机器语言)程序。
    • 2⃣️高级语言等编写的源代码,需要通过各自的编译器编译后,转换成本地代码。
    • 3⃣️通过调查本地代码的内容,可以了解程序最终是以何种形式来运行的。
    • 4⃣️如果直接打开本地代码来看的话,只能看到数值的罗列。
    • 5⃣️因而 就产生了这样一种想法,那就是在各本地代码中,附带上表示其功能的英语单词缩写。例如,在加法运算的本地代码中加上 add(addition 的缩写)、在比较运算的本地代码中加上 cmp(compare 的缩写)等。这 些缩写称为助记符,使用助记符的编程语言称为 汇编语言。
    • 6⃣️不过,即使是用汇编语言编写的源代码,最终也必须要转换成本 地代码才能运行。
    • 7⃣️负责转换工作的程序称为 汇编器转换这一处理本身称为 汇编
    • 8⃣️本地代码也可以反过来转换成汇编语言的源代码。持有该功能的逆变换程序称为 反汇编程序逆变换这一处理本身称为 反汇编

    2 通过编译器输出汇编语言的源代码

    除了将本地代码进行反汇编这一方法外,通过其他方式也可以获 取汇编语言的源代码。大部分C语言编译器,都可以把利用C语言编写的源代码转换成汇编语言的源代码,而不是本地代码。


    编译 生成的汇编语言源代码(一部分做了省略,彩色部分是转换成注 释的 C 语言源代码)

    3 不会转换成本地代码的伪指令

    汇编语言的源代码,是由转换成本地代码的指令(后面讲述的操作码)和针对汇编器的 伪指令构成的。伪指令负责把程序的构造及汇编的方法指示给汇编器(转换程序)。不过伪指令本身是无法汇编转换成本地代码的。

    这里我们把代码清单 10-2 中用到的伪指令部分摘出


    由伪指令 segment 和 ends 围起来的部分,是给构成程序的命令和 数据的集合体加上一个名字而得到的,称为 段定义

    • _TEXT 是指令的段定义,
    • _DATA 是被初始化(有初始值) 的数据的段定义,
    • _BSS 是尚未初始化的数据的段定义。
    • group 这一伪指令,表示的是把 _BSS_DATA 这两个段定义汇总为名为 DGROUP 的组。
    • _AddNum proc_AddNum endp 围起来的部分,以及 _MyFuncprocMyFunc endp 围起来的部分,分别表示 AddNum 函数和 MyFunc 函数的范围。
    • 伪指令 procendp 围起来的部分,表示的是过程(procedure)的范围。

    4 汇编语言的语法是“操作码 + 操作数”

    在汇编语言中,1 行表示对 CPU 的一个指令。汇编语言指令的语法结构是操作码 + 操作数(也存在只有操作码没有操作数的指令)。
    操作码表示的是指令动作操作数表示的是指令对象。


    本地代码加载到内存后才能运行。内存中存储着构成本地代码的 指令和数据。程序运行时,CPU 会从内存中把指令和数据读出,然后 再将其存储在 CPU 内部的寄存器中进行处理


    寄存器是 CPU 中的存储区域。不过,寄存器并不仅仅具有存储指令和数据的功能,也有运算功能。寄存器的名称会通过汇编语言的源代码指定给操作数。内存中的存储区域是用地址编号来区分的。CPU 内的寄存器 是用 eax 及 ebx 这些名称来区分的。

    5 最常用的 mov 指令

    指令中最常使用的是对寄存器和内存进行数据存储的 mov指令。 mov 指令的两个操作数,分别用来指定数据的存储地和读出源。

    操作数中可以指定寄存器、常数、标签(附加在地址前),以及用方括号[]围起来的这些内容。如果指定了没有用方括号围起来的内容, 就表示对该值进行处理;如果指定了用方括号围起来的内容,方括号 中的值则会被解释为内存地址,然后就会对该内存地址对应的值进行 读写操作。

    mov ebp,esp中,esp寄存器中的值被直接存储在了ebp寄存器中。 esp寄存器的值是100时ebp寄存器的值也是100。而在mov eax,dword ptr [ebp+8]的情况下,ebp寄存器的值加8后得到的值会被解释为内存 地址。如果 ebp 寄存器的值是 100 的话,那么 eax 寄存器中存储的就是 100 + 8 = 108 地址的数据。dword ptr(double word pointer)表示的是从 指定内存地址读出 4 字节的数据。

    6 对栈进行 push 和 pop

    程序运行时,会在内存上申请分配一个称为栈的数据空间。如该名称所表示的那样,数据 在存储时是从内存的下层(大的地址编号)逐渐往上层(小的地址编号)累积,读出时则是按照从上往下的顺利进行(图 10-3)的。

    是存储临时数据的区域,它的特点是通过 push 指令和 pop 指令 进行数据的存储和读出。往栈中存储数据称为“入栈”,从栈中读出数 据称为“出栈”。32 位 x86 系列的 CPU 中,进行 1 次 push 或 pop,即 可处理 32 位(4 字节)的数据。

    对栈进行读写的内存地址是由 esp 寄存 器(栈指针)进行管理的。push 指令和 pop 指令运行后,esp 寄存器的 值会自动进行更新(push 指令是 -4,pop 命令是 +4),因而程序员就没 有必要指定内存地址了。

    7 函数调用机制


    8 函数内部的处理


    “ 函数 的参数是通过栈来传递,返回值是通过寄存器来返回的”

    9 始终确保全局变量用的内存空间

    C 语言中, 在函数外部定义的变量称为 全局变量,在函数内部定义的变量称为 局部变量





    10 临时确保局部变量用的内存空间


    11 循环处理的实现方法

    12 条件分支的实现方法



  • 相关阅读:
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    自考感悟,话谈备忘录模式
    [每日一题] OCP1z0-047 :2013-07-26 alter table set unused之后各种情况处理
    Java实现 蓝桥杯 算法提高 p1001
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 拿糖果
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 求arccos值
    Java实现 蓝桥杯 算法提高 因式分解
    Java实现 蓝桥杯 算法提高 因式分解
  • 原文地址:https://www.cnblogs.com/cmi-sh-love/p/cheng-xu-shti-zen-yang-pao-qi-lai-de-du-shu-bi-jidi.html
Copyright © 2011-2022 走看看