本文随便整理,我们上微机原理之前没上汇编,无奈学校用的那本教材垃圾的超越想象力,根本就不是给初学者学习用的,整一个copy paste的产物,没头没尾,莫名其妙。所以只好整理一下Intel 汇编的知识了。本贴只是简单罗列,对他人作用不大。
首先是资料:在Visual Studio里面配置MASM
基本概念
程序运行
加载和执行:
- OS找文件,并得到其基本信息
- OS将文件载入内存
- OS执行一条分支转移指令,使CPU从程序的第一条机器指令开始执行,同时创建了一个进程
- OS见识进程并响应资源请求
- 进程结束后OS删除句柄,释放资源
IA32的体系结构
操作模式
- 保护模式: 所有指令和特性可用,程序具有独立的内存段,处理器阻止程序访问分配的段以外的其他内存
- 实地址模式:可以任意访问内存
- 系统管理模式:给开发操作系的人用的
基本执行环境
地址空间:保护模式4G,实模式1M
基本寄存器:
- 8个通用寄存器:EAX,EBX,ECX,EDX,EBP(基址指针),ESP(栈指针),ESI(Source Index),EDI(Destination Index)。前四组可以寻址到8位(EAX,AX,AH,AL),后四组只能寻址到16位(ESI,SI)
- 6个段寄存器:CS(Code),SS(Stack),DS(Data),ES,FS,GS
- EFLAGS
- 指令指针EIP(程序计数器)
详细的说明:
- EAX在乘除法时会自动被用
- 有些指令使用ECX做循环计数器
- ESP寻址栈上的数据,一般不用来做算术计算或者数据传送
- ESI和EDI有高速内存数据传送指令使用(中文翻译作扩展源/目标指针)
- EBP被高级语言用来做堆栈上的函数参数和局部变量引用,不应该用于算术运算和数据传送
实模式下段寄存器用于存放段基址。保护模式下则存放描述符表的指针。
EFLAGS是一系列标志,1时表示set了。0时表示reset了,标志包括:
- CF 进位-无符号运算时目的数无法容纳时为1
- OF 溢出-有符号运算溢出时为1
- SF 符号-负数为1
- ZF 零 -算术或逻辑运算为0时为1
- AC 辅助进位 - 算术运算时8位数的第3位向第4位进位时为1
- PF 奇偶- 结果的最低有效字节为1的位数为偶数时为1
内存管理
实模式
空间为0~FFFFF,段址和偏址都是16位,段址×16+偏址 = 绝对地址 08F1H:0100H = 09010H
保护模式
空间4GB,0~FFFFFFFF,masm中用flat模式。段寄存器存的是描述符表中的描述符。所有段都被映射到32位物理地址中。
一个程序至少要用2个段:代码段和数据段。段描述符存在全局描述符表中,是个64位的值。段界限符表示系统中物理内存数。在多段模式下每个进程都有自己的独立空间,界限副就保存期各自的空间。
此外,还有分页模式
汇编基础元素
常量
默认十进制,可加后缀 10H, 10D, 10O, 10B
可用基本整数表达式
()+- * / MOD
字符和字符串常量
'A', "A", "Goodnight" 'Goodnight'
保留字
- 指令助记符,MOV。。。
- 伪指令
- 属性 BYTE。。。
- 运算符
- 预定义符号,@data, 编译时返回整数常量值
标识符
标识变量、常量、过程。。
伪指令
内嵌的特殊代码,如 DWORD .data .code .stack 100h(表示运行时栈的大小)
根据书上示例解释汇编程序结构
这个程序的另外一种更加详细的写法:
程序skelton
汇编的过程
- 汇编器从源文件生成目标文件和列表文件
- 连接器读取目标文件从链接库里复制所需的过程和目标文件生成为可执行文件,还可以生成映像文件
列表文件包括程序的源代码、行号、偏移地址、翻译后的机器码和一个符号表,方便阅读
映像文件时包含被连接程序的分段信息的文本文件
定义数据
MASM的基本内部数据类型
- BYTE - 8bits unsigned integer
- SBYTE - 8bits signed integer
- WORD - 16bits unsinged integer 实模式下作近指针 NEAR
- SWORD - 16bits signed integer
- DWORD - 32bits (保护模式下做近指针)
- SDWORD - 32bits
- FWORD - 48位整数(保护模式下作远指针)
- QWORD - 64bits integer
- TBYTE - 80bits integer
- REAL4 - 32bits IEEE float
- REAL8 - 64bits ..
- REAL10 - 80bits .
还有DB,DW,DD(32bits 整数或实数),DQ(64bits 整数或实数),DT (10字节)
定义
注意的是,虽然课本上说字符串多行定义可以,但是实际上,貌似多行定义了以后用LENGTHOF操作只能得到一行的结果。这个需要进一步考证。
符号常量
符号常量实际上不占用存储空间,也不能修改
有三种伪指令用于这个: = EQU TEXTEQU
汇编语句基础
基础操作
基本运算指令
- INC/ DEC 自增自减
- ADD 目的数,源 源加到目的数上
- SUB 目的数,源
- NEG 求相反数(按位取反后+1,也就是求补)
符号位影响
- CF表示无符号整数运算是否溢出
- OF表示有符号整数运算是否溢出
- ZF表示结果是否为0
- SF表示结果是否为负
- PF表示目的操作数最低字节中的1是否偶数个
MOV系列
MOV系列都是数据传送指令,包括MOV, MOVZX, MOVSX
MOV指令有一些规则必须遵守:
- 两操作数尺寸相同
- 两操作数不能同时为内存操作数
- 目的操作数不允许是CS,EIP,IP
- 立即数不能直接送段寄存器(保护模式下不允许操作段寄存器)
对于尺寸不同的数之间数据传送就必须使用MOVZX和MOVSX,MOVZX是零扩展传送,也就是适用于传送无符号整数,指令会用0填充高位。而对于有符号数则用MOVSX
类似一个功能的是XCHG指令,用来交换两个操作数,但是注意它的两个操作数不能同时是内存操作数。
其他数据操作符
- OFFSET 返回一个变量相对于其所在段的开始地址的偏移量
- PTR 重载变量的默认尺寸
- TYPE 返回数组中每个原书的大小(字节数)
- LENGTHOF 返回数组内元素的个数
- SIZEOF 返回数组初始化时占用的字节数 = lengthof * Type
寻址
循环和条件
- jmp 无条件跳
- loop 使用ecx做计数器每次循环减1. 具体步骤是先ecx自减1,后看看是否为0,不是则调整到目的地址,否则不跳转。loop的跳转范围为-128~127字节(约42条指令)
使用loop做数组求和的例子
过程和条件处理
前提知识
运行时栈
CPU直接管理的内存数组,使用SS和ESP两个寄存器保护模式下,SS存段选择子ESP存的是只想堆栈内特定位置的一个32位偏移值,也就就是栈顶了。一般无需手工操作。运行时栈的增长是负的,也就是每压入一个值,栈顶指针ESP减小(一般是4)
对运行时栈的操作有PUSH POP, PUSHFD POPFD, PUSHAD PUSHA POPAD POPA这些
- PUSH压入16位或32位操作数,保护模式下总是32位的。
- PUSHFD用来压入32位的EFLAGS寄存器的值
- PUSHAD 按一下顺序压入寄存器:EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
- PUSHA类似的压入:AX, CX, DX, BX, SP, BP, SI, DI
定义和使用过程
汇编里的过程相当于高级语言里的函数。
所以,调用过程无法就是给寄存器赋值,再call一下。
此外,还可以使用USES 操作符来为PROC伪指令指定要使用的寄存器,它会自动生成push和pop相应寄存器的命令。这个操作符只需要写在PROC伪指令后面就可以
条件处理
相关指令
- AND dest, src . 总是清除溢出标志和进位标志, 操作数尺寸必须相同
- OR . 总是清除溢出和进位标志
- XOR .异或
- NOT reg[mem] .按位取反
- TEST .在每对操作数之间执行隐含的与操作,并置标志位。和AND的区别在于不修改目的操作数。
- BT,BTC,BTR,BTS . 。。。 暂时用不到
- CMP . 在每对操作数间进行隐含减法操作, 不修改操作数.
条件跳转指令
条件跳转都是成对的比如jz 就对应一个jnz,MASM要求跳转的目的地址在本过程内
- jz : if(ZF == 1) jump
- jc : if (CF == 1) jump
- jo : if (OF == 1) jump
- js : if( SF == 1) jump
- jp : if( PF == 1) jump
- je : 相等(CMP结果)则跳转
- jne: cmp 不等则跳
- jcxz: cx = 0 则跳
- ------------无符号数比较
- ja : if (left > right ) jump
- jae: if(left >= rhight) jump
- jb : if( left < right) jump
- jbe :..
- jnbe = ja
- -------------有符号数比较
- jl : cmp 小于则跳
- jg : cmp 大于则跳转
- jge :..
------------------------------------------未完待续-------------------------------------------------
p.s 贴出暂时要用的程序,从给定字符串计算某个子串出现的次数,写的不好,欢迎指正。