Assembly Language
不可视境界线最后变动于:2022年10月2日 下午
整这些有的没的不如看gas的官方文档
现在主要用到的就是gas, 所以整点gas基础的东西.
- If the symbol begins with a letter the statement is an assembly language instruction
汇编语言伪指令(最要命的
- 伪指令 (directive) 是嵌入源代码中的命令,由汇编器识别和执行。伪指令不在运行时执行,但是它们可以定义变量、宏和子程序;为内存段分配名称,执行许多其他与汇编器相关的日常任务。
- 简单来说就是方便编程的指令
基本:
.data .code .stack
定义段(segment).model flat,stdcall
它告诉汇编程序用的是哪一种存储模式.END
标记一个程序的结束
数据类型及伪指令
数据定义
类型 | 用法 |
---|---|
BYTE | 8 位无符号整数,B 代表字节 |
SBYTE | 8 位有符号整数,S 代表有符号 |
WORD | 16 位无符号整数 |
SWORD | 16 位有符号整数 |
DWORD | 32 位无符号整数,D 代表双(字) |
SDWORD | 32 位有符号整数,SD 代表有符号双(字) |
FWORD | 48 位整数(保护模式中的远指针) |
QWORD | 64 位整数,Q 代表四(字) |
TBYTE | 80 位(10 字节)整数,T 代表 10 字节 |
REAL4 | 32 位(4 字节)IEEE 短实数 |
REAL8 | 64 位(8 字节)IEEE 长实数 |
REAL10 | 80 位(10 字节)IEEE 扩展实数 |
还可以是传统数据定义伪指令,如下表所示。
伪指令 | 用法 | 伪指令 | 用法 |
---|---|---|---|
DB | 8位整数 | DQ | 64 位整数或实数 |
DW | 16 位整数 | DT | 定义 80 位(10 字节)整数 |
DD | 32 位整数或实数 |
初始化语句
1 |
|
如果希望不对变量进行初始化(随机分配数值),可以用符号 ? 作为初始值, 所有数值都由汇编器来转成二进制数据
BYTE and SBYTE
- 多初始值定义数组
1
2
3
4
5list BYTE 10,20,30,40
#甚至可以:
list BYTE 10,20,30,40
BYTE 50,60,70,80
BYTE 81,82,83,84- 定义字符串: 使用BYTE,
1
2
3
4
5greeting1 BYTE "Good afternoon",0
#也可以
greeting1 BYTE "Welcome to the Encryption Demo program "
BYTE "created by Kip Irvine.",0dh, 0ah
#还可以使用backslash分行- DUP 操作符: 使用一个整数表达式作为计数器,为多个数据项分配存储空间
1
2
3
4BYTE 4 DUP ( "STACK" ) ; 20 个字节:
#第一个数字是BYTE的个数, 第二个数字由DUP计算得出, 单位是字节
#提供了一种方便的方式来初始化数组:
array BYTE 5 DUP (?) ; 5 个数值,未初始化WORD and SWORD, DWORD, SDWORD, QWORD,
同BYTE和SBYTE
剩下还有浮点类型, BCD数据等等, 不看了
.DATA ?
伪指令声明未初始化数据。当定义大量未初始化数据时,.DATA ? 伪指令减少了编译程序的大小。等号=伪指令, 相当于宏定义一个数据, 可多次重复定义
当前地址计数器:
selfPtr DWORD $
让汇编器计算数组长度:
1
2list BYTE 10,20,30,40
ListSize = ($ - list) # 注意此时计算出来的是地址的差值, 所以单位是字节, 如果遇到WORD要注EQU伪指令, 无法多次定义
1
2
3name EQU expression #必须是整数表达式
name EQU symbol #任意一个用EQU或=定义过的符号
name EQU <text> #直接文本替换, 最像#define, 也可用来定义实数TEXTEQU 文本宏伪指令,
1
2
3name TEXTEQU <text> # 就是文本
name TEXTEQU textmacro # 前面的文本宏
name TEXTEQU %constExpr # 整数表达式
相关指令
操作数有 3 种基本类型:
- 立即数——用数字文本表达式
- 寄存器操作数——使用 CPU 内已命名的寄存器
- 内存操作数——引用内存位置
操作数 | 说明 |
---|---|
reg8 | 8 位通用寄存器:AH、AL、BH、BL、CH、CL、DH、DL |
reg16 | 16 位通用寄存器:AX、BX、CX、DX、SI、DI、SP、BP |
reg32 | 32 位通用寄存器:EAX、EEX、ECX、EDX、ESI、EDI、ESP、EBP |
reg | 通用寄存器 |
sreg | 16 位段寄存器:CS、DS、SS、ES、FS、GS |
imm | 8 位、16 位或 32 位立即数 |
imm8 | 8 位立即数,字节型数值 |
imm16 | 16 位立即数,字类型数值 |
imm32 | 32 位立即数,双字型数值 |
reg/mem8 | 8 位操作数,可以是 8 位通用寄存器或内存字节 |
reg/mem16 | 16 位立即数,可以是 16 位通用寄存器或内存字 |
reg/mem32 | 32 位立即数,可以是 32 位通用寄存器或内存双字 |
mem | 8位、16 位或 32 位内存操作数 |
4.9 OFFSET运算符 : 表示的是该数据标号距离数据段起始地址的距离
4.10 ALIGN伪指令 1,2,4,8,16字节对齐
4.11 PTR运算符
mov ax,WORD PTR myDouble
, 把一个DWORD的低两字节传入ax(因为是小端法存储, 而且可用偏移来传入
高两字节:mov ax,WORD PTR [myDouble+2]
)把两个小的移入大的:
1
2wordList WORD 5678h,1234h
mov eax, DWORD PTR wordList
4.12 TYPE运算符 返回变量的大小
4.13 LENGTHOF运算符 计算数组中元素的个数, 如果数组占据多行, 只计算第一行
4.14 LABEL伪指令 可以插入一个标号,并定义它的大小属性,但是不为这个标号分配存储空间
LongValue LABEL DWORD
标识下一个地址开始的DWORD字节
4.15 间接寻址 特殊: inc BYTE PTR [esi]
要加指针的类型, 剩下的有很多, 详见网站
4.16 JMP和LOOP指令 这个loop集成了ECX以及其他一些指令, 要看的话详见网站
汇编语言过程
压栈出栈, push&pop
PUSHFD 和 POPFD 指令: 压入和弹出EFLAGS寄存器
PUSHA (push all-16bits), PUSHAD (push all double-32bits), POPAD 和 POPA
PROC和ENDP :定义一个过程
1
2
3
4main PROC
.
.
main ENDP- 标号只有过程中的有效, 不过也可以定义全局标号
Destination::
, 使用两个引号即可, 尽量少用
- 标号只有过程中的有效, 不过也可以定义全局标号
USES 运算符: 在PROC 伪指令一行后面指出当前过程要修改的寄存器, 汇编器在头尾自动生成push和pop指令, 只对汇编器有效
链接库跳过
条件判断
操作 | 说明 |
---|---|
AND | 源操作数和目的操作数进行逻辑与操作 |
OR | 源操作数和目的操作数进行逻辑或操作 |
XOR | 源操作数和目的操作数进行逻辑异或操作 |
NOT | 对目标操作数进行逻辑非操作 |
TEST | 源操作数和目的操作数进行逻辑与操作,并适当地设置 CPU 标志位 |
- 置位和清除零标志位、符号标志位、进位标志位和溢出标志位的方法
- 汇编语言64位模式下的布尔指令:
- 32 位操作数是一个特殊的情况,需要与其他大小操作数的情况分开考虑。
- 条件跳转
- 注意无符号数和有符号数的比较是不同的.
- …