NASM源代码分析之NASM中的指令表示(1)
在汇编语言中,一般将一条指令写成一行。一条指令有不同的组成部分,分别是:
1) 地址/变量标识(label),例如:start:mov al,1中,start即为地址label。
2) 指令前缀,包括 times,rep,a32,lock等
3) 指令,如 mov,inc,
4) 操作数,例如: mov ax,12 , 12即为操作数,在NASM中,最多有3个操作数。
表示指令的数据结构为:
typedef struct { /* an instruction itself */
char *label; //标识(label)内容字符串
int prefixes[MAXPREFIX]; // 前缀,最多4个
int nprefix; // 当前表示的指令的前缀个数
int opcode; // 指令编号(每个指令都有一个数字编号)
int condition; // 条件指令,对于诸如jne,je,set等Jcc和SETcc等形式的条件指令,则opcode=Jcc或SETcc,conditions表示Jcc中cc的编号,例如指令jbe的conditions=3
int operands; // 操作数个数,db,dw之类不再此类限制,最多3个,[0,3]
operand oprs[3]; // 操作数编码
extop *eops; // 扩展操作数,例如用db,dw等定义的数
int eops_float; // 如果包含浮点数,则为true
long times; // 重复次数,由前缀times定义,例如语句:times 4 db 100; 则times=4
int forw_ref; // 操作数是否有前段引用
} insn;
NASM对源程序进行汇编,主要运行的函数是assemble_file(),对源程序进行2次汇编,其流程时:
第一遍:主要确定代码中各label信息
1. 从源代码文件中读取一行代码:line=preproc->getline(),若结束,至4。
2. 判断这个代码是否是NASM自带的汇编格式,若不是,跳至3。
包括:
a) [segment n] 或 [section n] : 定义段
b) [extern label:special] : 定义外部模块标识
c) [bits n] : 定义程序位数,0.98支持16和32位,之后的版本还支持64位。
d) [global symbol:special] : 定义全局变量/标识
e) [common symbol size:special] : 定义common型变量,相当于在段.bbs中定义全局变量
f) [absolute address] : 定义绝对label。
3. 调用parse_line()分析代码,跳至1。
第二遍:
4. 从源代码文件中读取一行代码:line=preproc->getline(),若结束,至7。
5. 判断这个代码是否是NASM自带的汇编格式,若不是,跳至3。
包括:
a) [segment n] 或 [section n] : 定义段
b) [extern label:special] : 定义外部模块标识
c) [bits n] : 定义程序位数,0.98支持16和32位,之后的版本还支持64位。
d) [global symbol:special] : 定义全局变量/标识
e) [common symbol size:special] : 定义common型变量,相当于在段.bbs中定义全局变量
f) [absolute address] : 定义绝对label。
6. 调用parse_line()分析代码,并将每行信息保存到结构output_ins中,并生成二进制内容输出到文件中,跳至4。
7. 清理内存,退出。