编译部分
// ----------------------------------------- assemble.cpp ------------------------------------------
// 此文件用于扫描汇编指令,得到扫描的符号,并检测操作数的合法性,最后可将某个语句编译成机器码
// 理解此文件需要理解机器码的格式
// 这是一个很有意思的文件
// Free Disassembler and Assembler -- Assembler
//
// Copyright (C) 2001 Oleh Yuschuk
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 16.01.2002 - corrected error in processing of immediate constants.
#define STRICT
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <dir.h>
#include <math.h>
#include <float.h>
#pragma hdrstop
#include "disasm.h"
#pragma warning(disable:4996) // 关闭旧函数声明警告
////////////////////////////////////////////////////////////////////////////////
///////////////////////////// ASSEMBLER FUNCTIONS //////////////////////////////
// Scanner modes.
#define SA_NAME 0x0001 // Don't try to decode labels
#define SA_IMPORT 0x0002 // Allow import pseudolabel
// Types of input tokens reported by scanner.
// 表示指令行结束
#define SCAN_EOL 0 // End of line
// 扫描到8位寄存器
#define SCAN_REG8 1 // 8-bit register
// 扫描到16位寄存器
#define SCAN_REG16 2 // 16-bit register
// 扫描到32位寄存器
#define SCAN_REG32 3 // 32-bit register
// 扫描到段寄存器
#define SCAN_SEG 4 // Segment register
// 扫描到FPU寄存器
#define SCAN_FPU 5 // FPU register
// 扫描到MMX寄存器
#define SCAN_MMX 6 // MMX register
// 扫描到控制寄存器
#define SCAN_CR 7 // Control register
// 扫描到调试寄存器
#define SCAN_DR 8 // Debug register
// 扫描到操作数据长度
#define SCAN_OPSIZE 9 // Operand size modifier
#define SCAN_JMPSIZE 10 // Jump size modifier
#define SCAN_LOCAL 11 // Address on stack in form LOCAL.decimal
#define SCAN_ARG 12 // Address on stack in form ARG.decimal
#define SCAN_PTR 20 // PTR in MASM addressing statements
#define SCAN_REP 21 // REP prefix
#define SCAN_REPE 22 // REPE prefix
#define SCAN_REPNE 23 // REPNE prefix
#define SCAN_LOCK 24 // LOCK prefix
#define SCAN_NAME 25 // Command or label
// 扫描到16进制常数
#define SCAN_ICONST 26 // Hexadecimal constant
// 扫描到10进制数
#define SCAN_DCONST 27 // Decimal constant
// 扫描到不明确的常量值
#define SCAN_OFS 28 // Undefined constant
// 扫描到浮点数
#define SCAN_FCONST 29 // Floating-point constant
#define SCAN_EIP 30 // Register EIP
#define SCAN_SIGNED 31 // Keyword "SIGNED" (in expressions)
#define SCAN_UNSIGNED 32 // Keyword "UNSIGNED" (in expressions)
#define SCAN_CHAR 33 // Keyword "CHAR" (in expressions)
#define SCAN_FLOAT 34 // Keyword "FLOAT" (in expressions)
#define SCAN_DOUBLE 35 // Keyword "DOUBLE" (in expressions)
#define SCAN_FLOAT10 36 // Keyword "FLOAT10" (in expressions)
#define SCAN_STRING 37 // Keyword "STRING" (in expressions)
#define SCAN_UNICODE 38 // Keyword "UNICODE" (in expressions)
#define SCAN_MSG 39 // Pseudovariable MSG (in expressions)
// 扫描到其他符号,如','
#define SCAN_SYMB 64 // Any other character
#define SCAN_IMPORT 65 // Import pseudolabel
// 扫描出错
#define SCAN_ERR 255 // Definitely bad item
// Definition used by Assembler to report command matching errors.
#define MA_JMP 0x0001 // Invalid jump size modifier
// 指令操作数个数有误
#define MA_NOP 0x0002 // Wrong number of operands
// 操作数类型有误
#define MA_TYP 0x0004 // Bad operand type
#define MA_NOS 0x0008 // Explicit operand size expected
// 操作数长度有误
#define MA_SIZ 0x0010 // Bad operand size
// 操作数大小不同
#define MA_DIF 0x0020 // Different operand sizes
#define MA_SEG 0x0040 // Invalid segment register
#define MA_RNG 0x0080 // Constant out of expected range
/**
* 用于存储汇编指令中某个操作数的相关信息
*/
typedef struct t_asmoperand
{
// 操作数类型
// REG:表示操作数是通用寄存器
// RST:表示操作数是FPU寄存器
// IMM:表示操作数是一个立即数
// JMF:表示操作数是jmp或call的地址
// SGM:表示操作数是一个段寄存器
// MXL:表示操作数是一个XLAT操作数 // XLAT operand ([EBX+AL])
// MRG:表示操作数包含 ModRM 寻址的信息
int type; // Operand type, see beginning of file
// 表明操作数的长度,如8位寄存器则为1,
// 16位寄存器则为2,32位寄存器则为4
int size; // Operand size or 0 if yet unknown
// 例如当type为某个寄存器时,指明操作相应寄存器的下标
int index; // Index or other register
int scale; // Scale
int base; // Base register if present
// 当操作数是一个立即数时,存储该立即数
// 当操作数是通过如OFFSET计算出的偏移量时,存放偏移量,但实际上偏移量的值是不明确的
long offset; // Immediate value or offset
// 表示offset的数存在,但其值不明确(即存放的可能是某个偏移量)
int anyoffset; // Offset is present but undefined
// 当操作数是 seg:offset 时,offset存储其偏移,segment存储seg段信息
int segment; // Segment in address if present
// 指定跳转指令的跳转地址修饰符,如FAR、NEAR、SHORT、LONG等
// SHORT:1,LONG:2,NEAR:4,FAR:8
int jmpmode; // Specified jump size
} t_asmoperand;
// 指向以0字符结束、要编译的源代码指令
static char * asmcmd; // Pointer to 0-terminated source line
/**
* 表明扫描的元素类型
* SCAN_REG8:表明是8位通用寄存器
* SCAN_FPU:表明是FPU寄存器
* SCAN_OPSIZE:表明是操作数长度修饰符,如BYTE
* SCAN_JMPSIZE:表明是jmp跳转指令跳转长度修饰符,如SHORT
* SCAN_REP:表明扫描到指令前缀:REP等
* SCAN_LOCK:表明扫描到指令前缀:LOCK
* SCAN_PTR:表明扫描到 PTR 修饰符
*
* SCAN_SIGNED: 表明扫描到各种数据类型修饰符
* SCAN_UNSIGNED
* SCAN_CHAR
* SCAN_FLOAT
* SCAN_DOUBLE
*
* SCAN_NAME:表明扫描到标识符名称、指令名等
*/
static int scan; // Type of last scanned element
// 当如idata为 || 等运算符时,prio代表该运算符的优先级
static int prio; // Priority of operation (0: highest)
// 存储最后扫描到的名字(如标识名,指令名等)
static char sdata[TEXTLEN]; // Last scanned name (depends on type)
/**
* 保存最后扫描到的元素值:
* 1、如果扫描到的是寄存器,则保存该寄存器编号
* 2、如果扫描到的是长度修饰符(见数组sizename[]),则是修饰符下标
* 3、如果扫描到的是jmp指令跳转长度修饰符,则如SHORT为1、LONG为2
* 4、如果扫描到的是SCAN_LOCAL,则表示 Local.decimal 后的 decimal
* 5、如果扫描到的是SCAN_ARG,则表示 Arg.decimal 后的 decimal
* 6、如果扫描到的是标识符名称、指令名等,则表示该名称的长度
* 7、如果扫描到的是数字,则保存数字值
* 8、如果扫描到的是字符,则保存该字符的ASCII码
* 实际上,当扫描到字符时,scan中存放的是SCAN_ICONST,表示扫描
* 到常数,由此可见,扫描到字符是以扫描到常数看待的
* 9、如果扫描到的是运算符,则存储之,例如 idata = '||'
* 10、如果扫描到的是SCAN_IMPORT,则存储import name
*/
static long idata; // Last scanned value
// 用于存储扫描到的浮点大数
static long double fdata; // Floating-point number
// 指向出错的内容
static char *asmerror; // Explanation of last error, or NULL
// Simple and slightly recursive scanner shared by Assemble(). The scanner is
// straightforward and ineffective, but high speed is not a must here. As
// input, it uses global pointer to source line asmcmd. On exit, it fills in
// global variables scan, prio, sdata, idata and/or fdata. If some error is
// detected, asmerror points to error message, otherwise asmerror remains
// unchanged.
/**
* 对汇编指令进行扫描,扫描结果存储至全局变量中:
* scan:存放扫描到的元素类型
* prio:如果扫描到的是运算符,则存储其优先级
* sdata:存放扫描元素的字符串
* idata:存放扫描元素的相关值
* fdata:同idata,当扫描到的元素是一浮点数时,保存该值
* asmerror:存放扫描过程中出现的错误信息
*
* mode:指明扫描模式
*
* 返回值:SCAN_ERR表明扫描中出现错误
* SCAN_EOL表明扫描结束
* ...
*/
static void Scanasm(int mode) // *
{
int i, j, base, maxdigit;
long decimal, hex;
long double floating, divisor;
char s[TEXTLEN], * pcmd;
sdata[0] = '\0';
idata = 0;
// 如果汇编指令为空,则出错
if (asmcmd == NULL)
{
asmerror = "NULL input line";
scan = SCAN_ERR;
return;
};
// 跳过汇编指令前的空格
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++; // Skip leading spaces
// 扫描到汇编指令结束符,则直接返回
if (*asmcmd == '\0' || *asmcmd == ';')
{
scan = SCAN_EOL;
return;
};
// 判断asmcmd是否以英文字母,或下划线,或@开头,是则表明可能是指令名、寄存器名或标识符名称...
if (isalpha(*asmcmd) || *asmcmd == '_' || *asmcmd == '@')
{
// 先保存首字符
sdata[0] = *asmcmd++;
// Some keyword or identifier
i = 1;
// 注:isalnum()用于判断字符是否是数字或字母
// 将指令后续内容复制到sdata[]中
while ((isalnum(*asmcmd) || *asmcmd == '_' || *asmcmd == '@') && i < sizeof(sdata))
sdata[i++] = *asmcmd++;
// 如果标识符长度超限制,则出错返回
if (i >= sizeof(sdata))
{
asmerror = "Too long identifier";
scan = SCAN_ERR;
return;
};
// 给扫描到的sdata名称添加结束符
sdata[i] = '\0';
// 再次跳过空格
while (*asmcmd == ' ' || *asmcmd=='\t')
// Skip trailing spaces
asmcmd++;
// 将sdata复制至s中,并转为大写字母
strcpy(s, sdata);
_strupr_s(s);
// 至此,s可能是指令名、寄存器名或标识符名称...
// 判断s是否是低8位寄存器,如AL、CL、DL等
for (j = 0; j <= 8; j++)
{
// j == 8 means "any register"
if (strcmp(s, regname[0][j]) != 0)
continue;
idata = j;
// 表示扫描结果是一个8位寄存器
scan = SCAN_REG8; // 8-bit register
return;
};
// 判断s是否是16位寄存器,如AX、CX、DX等
for (j = 0; j <= 8; j++)
{
if (strcmp(s, regname[1][j]) != 0)
continue;
idata = j;
scan = SCAN_REG16; // 16-bit register
return;
};
// 判断s是否是32位寄存器,如EAX、ECX、EDX等
for (j = 0; j <= 8; j++)
{
if (strcmp(s, regname[2][j]) != 0)
continue;
idata = j;
scan = SCAN_REG32; // 32-bit register
return;
};
// 判断s是否是段寄存器,如CS、SS等
for (j = 0; j < 6; j++)
{
if (strcmp(s, segname[j]) != 0)
continue;
idata = j;
scan = SCAN_SEG; // Segment register
// 跳过空格
// 问题:进入此判断前已经跳过一次了,怎么还需跳过 [??]
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++; // Skip trailing spaces
return;
};
// 判断是否扫描到FPU寄存器
if (strcmp(s, "ST") == 0)
{
// 先保存原汇编指令指针,以便需要时恢复
pcmd = asmcmd;
// 递归调用Scanasm()继续扫描
Scanasm(SA_NAME); // FPU register
// 后面的内容非 '(',即非"ST(",则不处理之,
// 并且将原扫描的ST当作FPU寄存器处理
if (scan != SCAN_SYMB || idata != '(')
{
// 恢复为原汇编指令
asmcmd = pcmd; // Undo last scan
idata = 0;
scan = SCAN_FPU;
return;
};
// 至此,说明扫描到的是 ST(,则继续扫描"("后的内容
Scanasm(SA_NAME);
// j 存储该扫描到的内容的值
j = idata;
// 检测在ST后是否是 0 - 7 的数 [ST0, ST1...ST7], 如果不是,则说明该FPU寄存器出错
if ((scan != SCAN_ICONST && scan != SCAN_DCONST) || idata < 0 || idata > 7)
{
asmerror = "FPU registers have indexes 0 to 7";
scan = SCAN_ERR;
return;
};
// 至此,说明前面扫描到的是ST([0-7]),则继续扫描
Scanasm(SA_NAME);
// 扫描不到")",说明不是ST([0-7]),则出错返回
if (scan != SCAN_SYMB || idata != ')')
{
asmerror = "Closing parenthesis expected";
scan = SCAN_ERR;
return;
};
// 至此,说明扫描到的是 ST([0-7])
idata = j;
scan = SCAN_FPU;
return;
};
// 判断是否是FPU寄存器,格式:ST[0 - 7]
for (j = 0; j <= 8; j++)
{
if (strcmp(s, fpuname[j]) != 0)
continue;
idata = j;
scan = SCAN_FPU; // FPU register (alternative coding)
return;
};
// 判断是否是MMX寄存器,如MM0、MM1
for (j = 0; j <= 8; j++)
{
if (strcmp(s, mmxname[j]) != 0)
continue;
idata = j;
scan = SCAN_MMX; // MMX register
return;
};
// 判断是否是控制寄存器,如CR0、CR1
for (j = 0; j <= 8; j++)
{
if (strcmp(s, crname[j]) != 0)
continue;
idata = j;
scan = SCAN_CR; // Control register
return;
};
// 判断是否调试寄存器,如DR0、DR1
for (j = 0; j <= 8; j++)
{
if (strcmp(s, drname[j]) != 0)
continue;
idata = j;
scan = SCAN_DR; // Debug register
return;
};
// 判断是否是数据长度修饰符
for (j = 0; j < sizeof(sizename) / sizeof(sizename[0]); j++)
{
if (strcmp(s, sizename[j]) != 0)
continue;
pcmd = asmcmd;
// 如果是数据长度修饰符,则继续扫描看是否带有PTR
Scanasm(SA_NAME);
// 如果不是如BYTE PTR格式,则恢复
if (scan != SCAN_PTR) // Fetch non-functional "PTR"
asmcmd = pcmd;
idata = j;
scan = SCAN_OPSIZE; // Operand (data) size in bytes
return;
};
// 判断是否是EIP寄存器
if (strcmp(s, "EIP") == 0)
{
// Register EIP
scan = SCAN_EIP;
idata = 0;
return;
};
// 判断是否是JMP指令跳转长度修饰符
if (strcmp(s, "SHORT") == 0)
{
// Relative jump has 1-byte offset
scan = SCAN_JMPSIZE;
idata = 1;
return;
};
if (strcmp(s, "LONG") == 0)
{
// Relative jump has 4-byte offset
scan = SCAN_JMPSIZE;
idata = 2;
return;
};
if (strcmp(s, "NEAR") == 0)
{
// Jump within same code segment
scan = SCAN_JMPSIZE;
idata = 4;
return;
};
if (strcmp(s, "FAR") == 0)
{
// Jump to different code segment
scan = SCAN_JMPSIZE;
idata = 8;
return;
};
// LOCAL是定义局部变量用的.用这个关键字是为了让编译器
// 给变量分配内存.
// 格式是:
// LOCAL 变量名:变量类型
// LOCAL.decimal
if (strcmp(s, "LOCAL") == 0 && *asmcmd == '.')
{
// 跳过"."
asmcmd++;
// 跳过空格
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++; // Skip trailing spaces
// 判断在LOCAL后是否是数字, LOCAL.后面必须是数字
if (!isdigit(*asmcmd))
{
asmerror = "Integer number expected";
scan = SCAN_ERR;
return;
};
// 获取 LOCAL. 后面的数字信息
while (isdigit(*asmcmd)) // LOCAL index is decimal number!
idata = idata * 10 + (*asmcmd++) - '0';
scan = SCAN_LOCAL;
return;
};
// ARG.decimal
if (strcmp(s, "ARG") == 0 && *asmcmd == '.')
{
asmcmd++;
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++; // Skip trailing spaces
if (!isdigit(*asmcmd))
{
asmerror = "Integer number expected";
scan = SCAN_ERR;
return;
};
while (isdigit(*asmcmd)) // ARG index is decimal number!
idata = idata * 10 + (*asmcmd++) - '0';
scan = SCAN_ARG;
return;
};
// 判断是否是REP前缀
if (strcmp(s, "REP") == 0)
{
scan = SCAN_REP;
return;
};
// 判断是否是REPE前缀
if (strcmp(s, "REPE") == 0 || strcmp(s, "REPZ") == 0)
{
scan = SCAN_REPE;
return;
};
// 判断是否是REPNE前缀
if (strcmp(s, "REPNE") == 0 || strcmp(s, "REPNZ") == 0)
{
scan = SCAN_REPNE;
return;
};
// 判断是否是LOCK前缀
if (strcmp(s, "LOCK") == 0)
{
scan = SCAN_LOCK;
return;
};
// 判断是否PTR
if (strcmp(s, "PTR") == 0)
{
scan = SCAN_PTR;
return;
};
// Undefined constant
// Present but undefined offset/constant
// OFFSET:在汇编中用于得到变量的偏址,偏址相当于一个常量,但该常量值并不明确多少(在哪)
if (strcmp(s, "CONST") == 0 || strcmp(s, "OFFSET") == 0)
{
scan = SCAN_OFS;
return;
};
// Keyword "SIGNED" (in expressions)
// 判断是否是有符号数
if (strcmp(s, "SIGNED") == 0)
{
scan = SCAN_SIGNED;
return;
};
// Keyword "UNSIGNED" (in expressions)
// 判断是否无符号数
if (strcmp(s, "UNSIGNED") == 0)
{
scan = SCAN_UNSIGNED;
return;
};
// Keyword "CHAR" (in expressions)
// 判断是数据类型CHAR
if (strcmp(s, "CHAR") == 0)
{
scan = SCAN_CHAR;
return;
};
// 判断是数据类型FLOAT
// Keyword "FLOAT" (in expressions)
if (strcmp(s, "FLOAT") == 0)
{
scan = SCAN_FLOAT;
return;
};
// Keyword "DOUBLE" (in expressions)
// 判断是数据类型DOUBLE
if (strcmp(s, "DOUBLE") == 0)
{
scan = SCAN_DOUBLE;
return;
};
// Keyword "FLOAT10" (in expressions)
// 判断是数据类型FLOAT10
if (strcmp(s, "FLOAT10") == 0)
{
scan = SCAN_FLOAT10;
return;
};
// Keyword "STRING" (in expressions)
// 判断是数据类型STRING
if (strcmp(s, "STRING") == 0)
{
scan = SCAN_STRING;
return;
};
// Keyword "UNICODE" (in expressions)
// 判断是数据类型UNICODE
if (strcmp(s, "UNICODE") == 0)
{
scan = SCAN_UNICODE;
return;
};
// Pseudovariable MSG (in expressions)
if (strcmp(s, "MSG") == 0)
{
scan = SCAN_MSG;
return;
};
// 至此,说明s是标签了,包括标识符名称、指令名等,无需对标签进行解码,则直接返回
if (mode & SA_NAME)
{
idata = i;
// Don't try to decode symbolic label
scan = SCAN_NAME;
return;
}
// 至此,说明此标识符无效,出错返回
asmerror = "Unknown identifier";
scan = SCAN_ERR;
return;
}
// 否则,如果扫描到的是数字
else if (isdigit(*asmcmd))
{
// Constant
// 数字基数
base = 0;
// 该数所属进制数最大数,如十进制为9,十六进制为15
maxdigit = 0;
// 存储该数字
decimal = hex = 0L;
floating = 0.0;
// Force hexadecimal number
// 数字以0X/0x开头,则是16进制数
if (asmcmd[0] == '0' && toupper(asmcmd[1]) == 'X')
{
// 基数为16
base = 16;
// 跳过数字的0X/0x
asmcmd += 2;
};
// 获取该数字
while (1)
{
// 如果是数字
if (isdigit(*asmcmd))
{
decimal = decimal * 10 + (*asmcmd) - '0';
floating = floating * 10.0 + (*asmcmd) - '0';
hex = hex * 16 + (*asmcmd) - '0';
// 默认最大数为9,即以十进制数算
if (maxdigit == 0)
maxdigit = 9;
asmcmd++;
}
// 否则,如果是16进制数的字母部分
else if (isxdigit(*asmcmd))
{
hex = hex * 16 + toupper(*asmcmd++) - 'A' + 10;
maxdigit = 15;
}
else
break;
};
// 如果进制的最大数为0,那就奇怪了
if (maxdigit == 0)
{
asmerror = "Hexadecimal digits after 0x... expected";
scan = SCAN_ERR;
return;
};
// 如果数字后为H字母,则也是16进制数
if (toupper(*asmcmd) == 'H')
{
// Force hexadecimal number
if (base == 16)
{
// 16进制数格式不应该为:0xXXXXH
asmerror = "Please don't mix 0xXXXX and XXXXh forms";
scan = SCAN_ERR;
return;
};
// 跳过 'H' 字符
asmcmd++;
// 保存该数字
idata = hex;
// 扫描到16进制常数
scan = SCAN_ICONST;
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++;
return;
};
// 可能是浮点数,必须是一个10进制数
if (*asmcmd == '.')
{
// Force decimal number
// 但如果不是10进制数,则出错
if (base == 16 || maxdigit > 9)
{
asmerror = "Not a decimal number";
scan = SCAN_ERR;
return;
};
asmcmd++;
// 如果带有小数,或是科学计数法
if (isdigit(*asmcmd) || toupper(*asmcmd) == 'E')
{
divisor = 1.0; // 除数
// 计算小数部分
while (isdigit(*asmcmd))
{
// Floating-point number
divisor /= 10.0;
floating += divisor * (*asmcmd - '0');
asmcmd++;
};
// 科学记数法
if (toupper(*asmcmd) == 'E')
{
asmcmd++;
if (*asmcmd == '-')
{
base = -1;
asmcmd++;
}
else
base = 1;
if (!isdigit(*asmcmd))
{
asmerror = "Invalid exponent";
scan = SCAN_ERR;
return;
};
decimal = 0;
while (isdigit(*asmcmd))
{
if (decimal < 65536L)
decimal = decimal * 10 + (*asmcmd++) - '0';
};
floating *= powl(decimal * base, 1);
};
fdata = floating;
// 扫描到一浮点数
scan = SCAN_FCONST;
return;
}
// 扫描到一10进制数
else
{
idata = decimal;
scan = SCAN_DCONST;
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++;
return;
};
};
//
idata = hex;
// Default is hexadecimal
// 默认情况下用16进制数
scan = SCAN_ICONST;
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++;
return;
}
// 否则,如果以 ' 开始,表示扫描到字符
else if (*asmcmd=='\'')
{
// Character constant
// 字符常量,跳过 ' 符号
asmcmd++;
if (*asmcmd == '\0' || (*asmcmd == '\\' && asmcmd[1] == '\0'))
{
asmerror = "Unterminated character constant";
scan = SCAN_ERR;
return;
};
// 空字符,出错返回
// 问题:为何不能使用空字符呢 [??]
if (*asmcmd == '\'')
{
asmerror = "Empty character constant";
scan = SCAN_ERR;
return;
};
// 跳过转义字符的 "\"
if (*asmcmd == '\\')
asmcmd++;
// 获取该字符的ASCII码
idata = *asmcmd++;
// 从这里看得出来,似乎只有一个字符
// 扫描结束字符
if (*asmcmd != '\'')
{
asmerror = "Unterminated character constant";
scan = SCAN_ERR;
return;
};
asmcmd++;
// 跳过空格部分
while (*asmcmd == ' ' || *asmcmd == '\t')
asmcmd++;
// 扫描到字符,相当于扫描到ASCII码,所以,
// 也将扫描结果作为常量看待
scan = SCAN_ICONST;
return;
}
// 否则,扫描到的可能是一些运算符
else
{
// Any other character or combination
// 存储首字符
idata = sdata[0] = *asmcmd++;
sdata[1] = sdata[2] = '\0';
// 判断是否逻辑运算符
if (idata == '|' && *asmcmd == '|')
{
// '||'
// 问题:'||'是一个字符吗 [??]
idata = '||';
prio = 10;
sdata[1] = *asmcmd++;
}
else if (idata == '&' && *asmcmd == '&')
{
// '&&'
idata = '&&';
prio = 9;
sdata[1] = *asmcmd++;
}
else if (idata == '=' && *asmcmd == '=')
{
// '=='
idata = '==';
prio = 5;
sdata[1] = *asmcmd++;
}
else if (idata == '!' && *asmcmd == '=')
{
// '!='
idata = '!=';
prio = 5;
sdata[1] = *asmcmd++;
}
else if (idata == '<' && *asmcmd == '=')
{
// '<='
idata = '<=';
prio = 4;
sdata[1] = *asmcmd++;
}
else if (idata == '>' && *asmcmd == '=')
{
// '>='
idata = '>=';
prio = 4;
sdata[1] = *asmcmd++;
}
else if (idata == '<' && *asmcmd == '<')
{
// '<<'
idata = '<<';
prio = 3;
sdata[1] = *asmcmd++;
}
else if (idata == '>' && *asmcmd == '>')
{
// '>>'
idata = '>>';
prio = 3;
sdata[1] = *asmcmd++;
}
// '|'
else if (idata == '|')
prio = 8;
// 异或运算符
// '^'
else if (idata == '^')
prio = 7;
else if (idata == '&')
prio = 6; // '&'
// 似乎表示是否是 include < 指令的 < 部分
else if (idata == '<')
{
if (*asmcmd == '&')
{
// Import pseudolabel (for internal use)
if ((mode & SA_IMPORT) == 0)
{
asmerror = "Syntax error";
scan = SCAN_ERR;
return;
};
asmcmd++;
i = 0;
// 获取import指令的import name
while (*asmcmd != '\0' && *asmcmd != '>')
{
sdata[i++] = *asmcmd++;
if (i >= sizeof(sdata))
{
asmerror = "Too long import name";
scan = SCAN_ERR;
return;
};
};
// import 指令必须 <&XXXX>
if (*asmcmd != '>')
{
asmerror = "Unterminated import name";
scan = SCAN_ERR;
return;
};
asmcmd++;
// 设置name的结束符
sdata[i] = '\0';
scan = SCAN_IMPORT;
return;
}
// 只是一个 < 号
else
prio = 4;
}
else if (idata == '>')
prio = 4; // '>'
else if (idata == '+')
prio = 2; // '+'
else if (idata == '-')
prio = 2; // '-'
else if (idata == '*')
prio = 1; // '*'
else if (idata == '/')
prio = 1; // '/'
else if (idata == '%')
prio = 1; // '%'
else if (idata == ']')
{
pcmd = asmcmd;
Scanasm(SA_NAME);
if (scan != SCAN_SYMB || idata != '[')
{
idata = ']';
asmcmd = pcmd;
prio = 0;
}
// 将 ][ 符号解析为 + 号
else
{
idata = '+';
prio = 2; // Translate '][' to '+'
};
}
// 否则,扫描到其他符号
else
prio = 0; // Any other character
// 其他符号
scan = SCAN_SYMB;
return;
};
};
// Fetches one complete operand from the input line and fills in structure op
// with operand's data. Expects that first token of the operand is already
// scanned. Supports operands in generalized form (for example, R32 means any
// of general-purpose 32-bit integer registers).
/**
* 对汇编指令操作数进行解析
*
* op: 用于返回解析的操作数
*/
static void Parseasmoperand(t_asmoperand * op) // *
{
int i, j, bracket, sign, xlataddr;
int reg, r[9];
long offset;
// No or bad operand
// 扫描不到操作数,或出错,则直接返回
if (scan == SCAN_EOL || scan == SCAN_ERR)
return;
// Jump or call address may begin with address size modifier(s) SHORT, LONG,
// NEAR and/or FAR. Not all combinations are allowed. After operand is
// completely parsed, this function roughly checks whether modifier is
// allowed. Exact check is done in Assemble().
// 跳转或call指令的地址可以用修饰符修饰,如SHORT、LONG、NEAR和FAR。并不是所有组
// 合都是允许的。此函数只是大要检测修饰是否允许,而更精确的检测在Assemble()中
// 如果扫描到Jump地址修饰符,如SHORT
if (scan == SCAN_JMPSIZE)
{
j = 0;
// 扫描并获取所有地址修饰符
while (scan == SCAN_JMPSIZE)
{
j |= idata; // Fetch all size modifiers
// 往下继续扫描看是否有修饰符
Scanasm(0);
};
// SHORT:1,LONG:2,NEAR:4,FAR:8
// 如果修饰符即有SHORT,又掺杂了LONG,则出错
if (((j & 0x03) == 0x03) || // Mixed掺杂 SHORT and LONG
((j & 0x0C) == 0x0C) || // Mixed NEAR and FAR
((j & 0x09) == 0x09)) // Mixed FAR and SHORT
{
asmerror = "Invalid combination of jump address modifiers";
scan = SCAN_ERR;
return;
};
// 如果未指定FAR,则强制为NEAR
if ((j & 0x08) == 0)
j |= 0x04; // Force NEAR if not FAR
// 保存跳转地址修饰符(模式)
op->jmpmode = j;
};
// Simple operands are either register or constant, their processing is
// obvious and straightforward.
// 最简单的操作数为寄存器操作数或立即数,他们的处理是显而易见和易懂的
// 扫描到8位或16位或32位通用寄存器
if (scan == SCAN_REG8 || scan == SCAN_REG16 || scan == SCAN_REG32)
{
// 表示操作数类型为寄存器操作
op->type = REG;
// 指明操作的目标寄存器的下标
op->index = idata; // Integer general-purpose register
// 保存操作数的长度值
if (scan == SCAN_REG8)
op->size = 1;
else if (scan == SCAN_REG16)
op->size = 2;
else
op->size = 4;
}
// 否则,如果是FPU寄存器操作
else if (scan == SCAN_FPU)
{
// FPU register
op->type = RST;
op->index = idata;
}
// 否则,如果是MMX寄存器
else if (scan == SCAN_MMX)
{
// MMX or 3DNow! register
op->type = RMX;
op->index = idata;
}
// 否则,如果是CR控制寄存器
else if (scan == SCAN_CR)
{
// Control register
op->type = CRX;
op->index = idata;
}
// 否则,如果是调试寄存器
else if (scan == SCAN_DR)
{
// Debug register
op->type = DRX;
op->index = idata;
}
// 至此,说明扫描到的不是寄存器操作数
// 否则,如果是其他符号,负数...
else if (scan == SCAN_SYMB && idata == '-')
{
// 负数
Scanasm(0); // Negative constant
// 扫描到的不是数字,则出错
if (scan != SCAN_ICONST && scan != SCAN_DCONST && scan != SCAN_OFS)
{
asmerror = "Integer number expected";
scan = SCAN_ERR;
return;
};
// 操作类型为直接数操作
op->type = IMM;
// 保存直接数或偏移
op->offset = -idata;
if (scan == SCAN_OFS)
// 表示offset数存在,但该值不明确
op->anyoffset = 1;
}
// 操作数是一个 正数
else if (scan == SCAN_SYMB && idata == '+')
{
// 扫描是否是一个正数
Scanasm(0); // Positive constant
// 如果扫描不到一整数,则出错返回
if (scan != SCAN_ICONST && scan != SCAN_DCONST && scan != SCAN_OFS)
{
asmerror = "Integer number expected";
scan = SCAN_ERR;
return;
};
// 操作数是一直接数
op->type = IMM;
op->offset = idata;
// 如果该操作数是一个偏移地址
if (scan == SCAN_OFS)
op->anyoffset = 1;
}
// 扫描到直接数或偏移地址(值不明确的直接数)
else if (scan == SCAN_ICONST || scan == SCAN_DCONST || scan == SCAN_OFS)
{
j = idata;
// 扫描到的是偏移
if (scan == SCAN_OFS)
// 表示该直接数的值不明确
op->anyoffset = 1;
// 扫描直接数后的内容
Scanasm(0);
// 扫描是否 seg:offset 格式地址
if (scan == SCAN_SYMB && idata == ':')
{
Scanasm(0); // Absolute long address (seg:offset)
// 如果 seg: 后不是一偏移地址,则出错
if (scan != SCAN_ICONST && scan != SCAN_DCONST && scan != SCAN_OFS)
{
asmerror = "Integer address expected";
scan = SCAN_ERR;
return;
};
// 操作数是一跳转地址
op->type = JMF;
// 偏移地址
op->offset = idata;
// 段地址
op->segment = j;
if (scan == SCAN_OFS)
op->anyoffset = 1;
}
// 否则,说明操作数是一个直接数
else
{
op->type = IMM;
// offset保存该直接数
op->offset = j; // Constant without sign
return; // Next token already scanned
};
}
// 否则,如操作数是一个浮点数,命令是不能带浮点数的,所以出错返回
else if (scan == SCAN_FCONST)
{
asmerror = "Floating-point numbers are not allowed in command";
scan = SCAN_ERR;
return;
}
// 指令格式: mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678
// Segment register or address.
// 段寄存器或地址
else if (scan == SCAN_SEG || scan == SCAN_OPSIZE || (scan == SCAN_SYMB && idata == '['))
{
// Segment register or address
bracket = 0; // 括弧
// 段寄存器
if (scan == SCAN_SEG)
{
// 保存段寄存器编号
j = idata;
Scanasm(0);
// 判断是否为 seg:offset,如果不是,则说明扫描到的只是一个段寄存器
if (scan != SCAN_SYMB || idata != ':')
{
// Segment register as operand
// 操作数是段寄存器
op->type = SGM;
op->index = j;
return; // Next token already scanned
};
// 以 seg:offset 出现,则保存段寄存器编号
op->segment = j;
// 扫描以获得 offset
Scanasm(0);
};
// Scan 32-bit address. This parser does not support 16-bit addresses.
// First of all, get size of operand (optional可选), segment register (optional)
// and opening bracket (required).
while (1)
{
// 扫描到 [
if (scan == SCAN_SYMB && idata == '[')
{
// 如果前面已扫描到此符号,则出错返回
if (bracket)
{
// Bracket
asmerror = "Only one opening bracket allowed";
scan = SCAN_ERR;
return;
};
// 表示扫描到 [
bracket = 1;
}
// 扫描到操作数大小修饰符,如BYTE
else if (scan == SCAN_OPSIZE)
{
// 操作数大小修饰符重复
if (op->size != 0)
{
// Size of operand
asmerror = "Duplicated size modifier修饰语";
scan = SCAN_ERR;
return;
};
op->size = idata;
}
// 扫描到段寄存器
else if (scan == SCAN_SEG)
{
// 段寄存器重复
if (op->segment != SEG_UNDEF)
{
// Segment register
asmerror = "Duplicated segment register";
scan = SCAN_ERR;
return;
};
// 保存段寄存器编号
op->segment = idata;
Scanasm(0);
if (scan != SCAN_SYMB || idata != ':')
{
asmerror = "Semicolon分号 expected";
scan = SCAN_ERR;
return;
};
}
else if (scan == SCAN_ERR)
return;
else
break; // None of expected address elements
Scanasm(0);
};
// 地址必须包含有 [ 符号
if (bracket == 0)
{
asmerror = "Address expression requires brackets";
scan = SCAN_ERR;
return;
};
// Assembling a 32-bit address may be a kind of nightmare恶梦, due to a large
// number of allowed forms. Parser collects immediate offset in op->offset
// and count for each register in array r[]. Then it decides whether this
// combination is valid and determines scale, index and base. Assemble()
// will use these numbers to select address form (with or without SIB byte,
// 8- or 32-bit offset, use segment prefix or not). As a useful side effect
// of this technique, one may specify, for example, [EAX*5] which will
// correctly assemble to [EAX*4+EAX].
// 编译一个32位地址简直是一个恶梦,因为对于地址有大量的格式可以使用。解析程序
// 将收集直接数偏移地址存放于op->offset中,与寄存器相关的地址信息则统计到 r[]
// 数组中。并决定该地址组合是否有效,确定scale,index与base的值。Assemble()函
// 数将会使用这些值进行确定地址格式(是否需要SIB字节来进行寻址,8位还是32位偏
// 址,是否使用段前缀等)。作为一个非常有效的技术,举例:[EAX * 5] 可以被正确
// 编译为 [EAX * 4 + EAX]
// 初始化寄存器值,该数组用于统计在地址中对寄存器的使用情况
for (i = 0; i <= 8; i++)
r[i] = 0;
// 默认符号
sign = '+'; // Default sign for the first operand
xlataddr = 0;
while (1)
{
// Get SIB and offset
// 扫描到 符号,则保存之
if (scan == SCAN_SYMB && (idata == '+' || idata == '-'))
{
sign = idata;
// 往下扫描符号后面的数
Scanasm(0);
};
// 出错,直接返回
if (scan == SCAN_ERR)
return;
// 语法错误
if (sign == '?')
{
asmerror = "Syntax error";
scan = SCAN_ERR;
return;
};
// XLAT:查表指令 XLAT
// 指令格式:XLAT TABLE 其中TABLE为一待查表格的首地址。
// 指令功能:把待查表格的一个字节内容送到AL累加器中。在执行该指令前,
// 应将TABLE先送至BX寄存器中,然后将待查字节与其在表格中距表首
// 地址位移量送AL,即(AL)<--((BX)+(AL)). 执行XLAT将使待查内容送
// 到累加器。
// 本指令不影响状态标位,表格长度不超过256字节。
// Register AL appears as part of operand of (seldom很少 used) command XLAT.
// 因为作为操作数使用8位AL寄存器是很少见的,所以如果出现,则可能使用了XLAT指令
if (scan == SCAN_REG8 && idata == REG_EAX)
{
// 寄存器前不能使用 - 符号
if (sign == '-')
{
asmerror = "Unable to subtract register";
scan = SCAN_ERR;
return;
};
if (xlataddr != 0)
{
asmerror = "Too many registers";
scan = SCAN_ERR;
return;
};
// 假设使用了XLAT指令
xlataddr = 1;
Scanasm(0);
}
// 不支持16位寄存器作为地址
else if (scan == SCAN_REG16)
{
asmerror = "Sorry, 16-bit addressing is not supported";
scan = SCAN_ERR;
return;
}
// 32位寄存器地址
else if (scan == SCAN_REG32)
{
if (sign == '-')
{
asmerror = "Unable to subtract register";
scan = SCAN_ERR;
return;
};
// 保存寄存器编号
reg = idata;
// 继续扫描
Scanasm(0);
// 如果是如上格式 EAX * 4,*后面的数字称为scale
if (scan == SCAN_SYMB && idata == '*')
{
// 扫描 scale
Scanasm(0); // Try index*scale
if (scan == SCAN_ERR)
return;
// 不明确的scale是不允许使用不明确的值
if (scan == SCAN_OFS)
{
asmerror = "Undefined scale is not allowed";
scan = SCAN_ERR;
return;
};
// 如果扫描到的不是 常量值 ,则不能作为scale使用,语法错误
if (scan != SCAN_ICONST && scan != SCAN_DCONST)
{
asmerror = "Syntax error";
scan = SCAN_ERR;
return;
};
// scale的值只能是:1,2,4,8。当在地址中出现如5的scale时,将
// 其当成4使用,但如果出现6、7等,则不能使用
if (idata == 6 || idata == 7 || idata > 9)
{
asmerror = "Invalid scale";
scan = SCAN_ERR;
return;
};
// 计算reg寄存器的总 scale
r[reg] += idata;
Scanasm(0);
}
// 否则,说明 scale = 1
else
r[reg]++;
} // Simple register
// 以下两个部分不太理解
// LOCAL是定义局部变量用的.用这个关键字是为了让编译器
// 给变量分配内存.
// 格式是: LOCAL 变量名:变量类型
else if (scan == SCAN_LOCAL)
{
r[REG_EBP]++;
// 在堆栈上分配 idata * 4 空间用于存放局部变量 [??]
op->offset -= idata * 4;
Scanasm(0);
}
// ARG r_Kernel32 : DWORD
// push r_Kernel32
// call Whereis_GPA
// 伪操作符arg的作用是,容许你输入一段字符或者数字作为
// 一个函数的参数(只在 pwb环境中)
else if (scan == SCAN_ARG)
{
r[REG_EBP]++;
op->offset += (idata + 1) * 4;
Scanasm(0);
}
// 扫描到直接数,则地址可能以scale * index出现
else if (scan == SCAN_ICONST || scan == SCAN_DCONST)
{
offset = idata;
Scanasm(0);
if (scan == SCAN_SYMB && idata == '*')
{
// 尝试是否 4 * EAX 等格式
Scanasm(0); // Try scale * index
if (scan == SCAN_ERR)
return;
// 寄存器前不能加 - 号
if (sign == '-')
{
asmerror = "Unable to subtract register";
scan = SCAN_ERR;
return;
};
// 不支持16位寄存器地址
if (scan == SCAN_REG16)
{
asmerror = "Sorry, 16-bit addressing is not supported";
scan = SCAN_ERR;
return;
};
// 必须是32位寄存器
if (scan != SCAN_REG32)
{
asmerror = "Syntax error";
scan = SCAN_ERR;
return;
};
// 无效的scale
if (offset == 6 || offset == 7 || offset > 9)
{
asmerror = "Invalid scale";
scan = SCAN_ERR;
return;
};
// 统计该寄存器的scale值
r[idata] += offset;
// 继续扫描后面的部分
Scanasm(0);
}
// 在scale后面没有 * 寄存器,则说明是偏移量
else
{
if (sign == '-')
op->offset -= offset;
else
op->offset += offset;
};
}
else if (scan == SCAN_OFS)
{
Scanasm(0);
// 如果ofs作为scale用,但因为ofs不明确,所以是不允许的
if (scan == SCAN_SYMB && idata == '*')
{
asmerror = "Undefined scale is not allowed";
scan = SCAN_ERR;
return;
}
// 否则,说明不是用于scale,则表示是一偏移
else
{
op->anyoffset = 1;
};
}
// 不属于以上情况,则跳地址无关,跳出循环
else
break; // None of expected address elements
// 如果已扫描到地址结束符 ],则结束
if (scan == SCAN_SYMB && idata == ']')
break;
// 至此,说明上面所有扫描无法得到有效结果,
// 则将sign置为 ? 表示上面的扫描有问题
sign = '?';
};
// 扫描出错,直接返回
if (scan == SCAN_ERR)
return;
// 扫描不到 ']',则语法错误
if (scan != SCAN_SYMB || idata != ']')
{
asmerror = "Syntax error";
scan = SCAN_ERR;
return;
};
// Process XLAT address separately.
// 如果确实扫描到XLAT地址,则检测其格式是否OK
if (xlataddr != 0)
{
// XLAT address in form [EBX+AX]
// 这里似乎只是为检测除EBX寄存器外,是否还使用了其他寄存器
// 作为地址使用,当然,对XLAT,基址只使用EBX,所以,如果有
// 其他寄存器作为地址使用,或还指明了偏址,那将是错误的
for (i = 0; i <= 8; i++)
{
// Check which registers used
if (i == REG_EBX)
continue;
if (r[i] != 0)
break;
};
if (i <= 8 || r[REG_EBX] != 1 || op->offset != 0 || op->anyoffset != 0)
{
asmerror = "Invalid address";
scan = SCAN_ERR;
return;
};
// XLAT操作数
op->type = MXL;
}
// Determine scale, index and base.
// 否则,说明是真正的地址了,现在需要确定scale,index与base了
else
{
j = 0; // Number of used registers
for (i = 0; i <= 8; i++)
{
// i寄存器未被使用作为地址部分,跳过
if (r[i] == 0)
continue; // Unused register
// 如果scale值为3、5或9
if (r[i] == 3 || r[i] == 5 || r[i] == 9)
{
// 如果index存在,或基址存在
if (op->index >= 0 || op->base >= 0)
{
if (j == 0)
asmerror = "Invalid scale";
else
asmerror = "Too many registers";
scan = SCAN_ERR;
return;
};
op->index = op->base = i;
// scale 只能是:1、2、4、8
op->scale = r[i] - 1;
}
else if (r[i] == 2 || r[i] == 4 || r[i] == 8)
{
// 已经有用于index的寄存器
if (op->index >= 0)
{
if (j <= 1)
asmerror = "Only one register may be scaled";
else
asmerror = "Too many registers";
scan = SCAN_ERR;
return;
};
op->index = i;
op->scale = r[i];
}
// 如果 i 寄存器使用计数为1,则可能是base,也可能是index
else if (r[i] == 1)
{
// 如果base还不存在,则将其作为base,这种可能性更高
if (op->base < 0)
op->base = i;
// 否则,index未指定,则作为index用,并且scale为1
else if (op->index < 0)
{
op->index = i;
op->scale = 1;
}
// 而如果既指定了index又指定了base,那么说明扫描到太多的寄存器,出错
else
{
asmerror = "Too many registers";
scan = SCAN_ERR;
return;
};
}
// 错误的scale
else
{
asmerror = "Invalid scale";
scan = SCAN_ERR;
return;
};
// 统计用于地址的寄存器数
j++;
};
// 操作数包含了 ModRM 寻址信息
op->type = MRG;
};
}
// 否则,说明是系统不支持的操作数
else
{
asmerror = "Unrecognized operand";
scan = SCAN_ERR;
return;
};
// In general, address modifier is allowed only with address expression which
// is a constant, a far address or a memory expression. More precise check
// will be done later in Assemble().
// 如果是一个JMP指令,并且操作数不是直接数,并且也不是地址,并且也不未包含 ModRM 的地址,则出错
if (op->jmpmode != 0 && op->type != IMM && op->type != JMF && op->type != MRG)
{
asmerror = "Jump address modifier is not allowed";
scan = SCAN_ERR;
return;
};
// 扫描下一符号
Scanasm(0); // Fetch next token from input line
};
// Function assembles text into 32-bit 80x86 machine code. It supports imprecise不精确的,不确定的
// operands操作数 (for example, R32 stays for any general-purpose 32-bit register).
// This allows to search for incompletei不完全的 commands. Command is precise when all
// significant bytes in model.mask are 0xFF. Some commands have more than one
// decoding. By calling Assemble() with attempt=0,1... and constsize=0,1,2,3 one
// gets also alternative variants (bit 0x1 of constsize is responsible for size
// of address constant and bit 0x2 - for immediate data). However, only one
// address form is generated ([EAX*2], but not [EAX+EAX]; [EBX+EAX] but not
// [EAX+EBX]; [EAX] will not use SIB byte; no DS: prefix and so on). Returns
// number of bytes in assembled code or non-positive number in case of detected
// error. This number is the negation of the offset in the input text where the
// error encountered. Unfortunately, BC 4.52 is unable to compile the switch
// (arg) in this code when any common subexpression optimization is on. The
// next #pragma statement disables all optimizations.
//#pragma option -Od // No optimizations, or BC 4.52 crashes
// 将cmd编译为机器指令并通过model返回
// errtext:返回编译的出错信息
// 返回值:指令长度
int Assemble(char * cmd, ulong ip, t_asmmodel * model, int attempt, int constsize, char * errtext)
{
// bytesize:为1表示只允许操作数为1个字节长度
int i, j, k, namelen, nameok, arg, match, datasize, addrsize, bytesize, minop, maxop;
int rep, lock, segment, jmpsize, jmpmode, longjump;
int hasrm, hassib, dispsize, immsize;
int anydisp, anyimm, anyjmp;
long l, displacement, immediate, jmpoffset = 0;
// name:存储指令完整助记符,包括指令前缀(如REP)与助记符
// nameend:指向指令助记符(指令名)的末尾
char name[32], * nameend;
// 存储编译后的指令机器码,长度不超15字节
char tcode[MAXCMDSIZE], tmask[MAXCMDSIZE];
// 存储指令3个操作数信息,指令最多可以有3个操作数
t_asmoperand aop[3], *op; // Up to 3 operands allowed
const t_cmddata * pd;
// 代码长度为0
if (model != NULL)
model->length = 0;
// 检测参数的合法性
if (cmd == NULL || model == NULL || errtext == NULL)
{
// 参数出错,则保存错误信息并返回
if (errtext != NULL)
strcpy(errtext, "Internal OLLYDBG error");
return 0;
}; // Error in parameters
// 保存欲编译的汇编指令
asmcmd = cmd;
// 指令是否有REP或LOCK前缀
rep = lock = 0;
errtext[0] = '\0';
// 扫描指令
Scanasm(SA_NAME);
// 指令结束,则不需要做任何操作
if (scan == SCAN_EOL) // End of line, nothing to assemble
return 0;
// 扫描指令前缀
while (1)
{
// Fetch all REPxx and LOCK prefixes
// 如果是REP或REPE或REPNE前缀,则...
if (scan == SCAN_REP || scan == SCAN_REPE || scan == SCAN_REPNE)
{
// 指令的REP前缀重复,出错返回
if (rep != 0)
{
strcpy(errtext, "Duplicated REP prefix");
goto error;
};
rep = scan;
}
// 否则,如果是LOCK前缀(用于加锁总线)
else if (scan == SCAN_LOCK)
{
// 同样,如果LOCK前缀重复,也出错返回
if (lock != 0)
{
strcpy(errtext, "Duplicated LOCK prefix");
goto error;
};
lock = scan;
}
else
// 未发现更多前缀,跳出循环
// No more prefixes
break;
// 往下扫描
Scanasm(SA_NAME);
};
// 扫描不到指令助记符(即指令名),则出错
if (scan != SCAN_NAME || idata > 16)
{
strcpy(errtext,"Command mnemonic助记符 expected");
goto error;
};
// 指向指令结束符并将指令转为大写
nameend = asmcmd;
strupr(sdata);
// Prepare full mnemonic (including repeat prefix, if any).
// 与前缀组合成完整助记符
if (rep == SCAN_REP)
sprintf(name, "REP %s", sdata);
else if (rep == SCAN_REPE)
sprintf(name, "REPE %s", sdata);
else if (rep == SCAN_REPNE)
sprintf(name, "REPNE %s", sdata);
else
strcpy(name, sdata);
// 至此,name可能如:REPX 指令助记符
// 往下扫描指令的操作数
Scanasm(0);
// 接下来需要解析命令的操作数(最多3个)
// Parse command operands (up to 3). Note: jump address is always
// the first (and only) operand in actual command set.
// 初始化3个操作数结构信息
for (i = 0; i < 3; i++)
{
aop[i].type = NNN; // No operand
aop[i].size = 0; // Undefined size
aop[i].index = -1; // No index
aop[i].scale = 0; // No scale
aop[i].base = -1; // No base
aop[i].offset = 0; // No offset
aop[i].anyoffset = 0; // No offset
aop[i].segment = SEG_UNDEF; // No segment
aop[i].jmpmode = 0;
}; // No jump size modifier
// 解析第一个操作数
Parseasmoperand(aop + 0);
// 获取跳转模式
jmpmode = aop[0].jmpmode;
// 如果存在跳转模式,则表示是一跳转指令,最高位置1
if (jmpmode != 0)
jmpmode |= 0x80; // 10000000b
// 在Parseasmoperand()函数中会调用Scanasm()往下扫描指令
// 第1个操作数后是 ','符号,则扫描第2个操作数并解析之
if (scan == SCAN_SYMB && idata == ',')
{
// 扫描第2个操作数并解析之
Scanasm(0);
Parseasmoperand(aop + 1);
// 还存在第3个操作数,则继续扫描之
if (scan == SCAN_SYMB && idata == ',')
{
// 扫描第3个操作数并解析之
Scanasm(0);
Parseasmoperand(aop + 2);
};
};
// 扫描出错,获取出错信息并返回
if (scan == SCAN_ERR)
{
strcpy(errtext, asmerror);
goto error;
};
// 操作数结束后,指令还存在其他内容,那就奇怪了
if (scan != SCAN_EOL)
{
strcpy(errtext, "Extra input after operand");
goto error;
};
// If jump size is not specified, function tries to use short jump. If
// attempt fails, it retries with long form.
// 如果跳转指令的跳转地址大小(如SHORT,FAR)未指令,则函数尝试使用SHORT
// 如果尝试失败,则尝试LONG跳转
longjump = 0; // Try short jump on the first pass
retrylongjump:
nameok = 0;
// Some commands allow different number of operands. Variables minop and
// maxop accumulate their minimal and maximal counts. The numbers are not
// used in assembly process but allow for better error diagnostics.
// 指令最多、最少操作数数量,用于限制指令的操作数个数
minop = 3;
maxop = 0;
// Main assembly loop: try to find the command which matches all operands,
// but do not process operands yet.
// 现在开始检测上面扫描到的指令与操作数是否匹配,是否OK
// 指令长度
namelen = (int)strlen(name);
// 遍历处理器有效的(机器)指令列表,以检测上面扫描的指令是否OK
for (pd = cmddata; pd->mask != 0; pd++)
{
// 如果指令助记符以&开始,则对助记符进行译码依赖于操作数长度
// 例如:
// &PUSHA*
// &CBW:CWDE
if (pd->name[0] == '&')
{
// Mnemonic助记符 depends on operand size
// 跳过助记符前的&符号
j = 1;
// 数据长度默认为16位
datasize = 2;
// 地址长度默认为32位
addrsize = 4;
while (1)
{
// 某些指令可以有多个助记符,每个助记符以 :分开,所以检测时需对所有助记符进行匹配
// Try all mnemonics (separated by ':')
for (i = 0; pd->name[j] != '\0' && pd->name[j] != ':'; j++)
{
// 指令助记符名称中,可以包含有字符'W'或'D',用于表示指令的操作数长度,这种指令
// 的译码结果往往操作数的长度起到很重要的决定作用
// 如果助记符有*符号,则表示该助记符中在*号位
// 置可能包含'W'或'D'以指示操作数长度
if (pd->name[j] == '*')
{
// 如果扫描到的助记符包含'W',说明操作数长度为16位(字)
if (name[i] == 'W')
{
datasize = 2;
i++;
}
// 如果扫描到的助记符包含'D',说明操作数长度为32位(双字)
else if (name[i] == 'D')
{
datasize = 4;
i++;
}
// 如果没通过'W'或'D'指明操作数长度,则根据sizesens处理
else if (sizesens == 0)
datasize = 2;
else
datasize = 4;
}
// 检测pd助记符与扫描的助记符是否匹配
else if (pd->name[j] == name[i])
i++;
else
break;
};
// 如果扫描的助记符与pd列表助记符相符,则找到指令信息,跳出循环
if (name[i] == '\0' && (pd->name[j] == '\0' || pd->name[j] == ':'))
break; // Bingo!
// 否则,说明助记符与pd不符,则需要搜索下一pd,如上例子
// &CBW:CWDE,搜索CBW不符后,则需要搜索CWDE指令看是否相符
while (pd->name[j] != '\0' && pd->name[j] != ':')
j++;
// 如果助记符确实以&CBW:CWDE出现,则需要检测:后的助记符是否与扫描到的助记符是否相符
// 注:以 : 作为助记符分割的指令,一般前部分是16位指令,而后部分是32位指令
if (pd->name[j] == ':')
{
j++;
datasize = 4;
} // Retry with 32-bit mnenonic
// 否则,只好搜索下一pd指令了
else
{
i = 0;
break; // Comparison failed
};
};
if (i == 0)
continue;
}
// 否则,如果指令助记符以 $ 开始,则对助记符进行译码依赖于地址长度
// 此处操作同上,略
else if (pd->name[0] == '$') // Mnemonic depends on address size
{
// 跳过 $ 符号
j = 1;
datasize=0;
addrsize=2;
while (1)
{
// Try all mnemonics (separated by ':')
for (i = 0; pd->name[j] != '\0' && pd->name[j] != ':'; j++)
{
if (pd->name[j] == '*')
{
// 如果地址大小为 16位
if (name[i] == 'W')
{
addrsize = 2;
i++;
}
// 否则,如果为32位
else if (name[i] == 'D')
{
addrsize = 4;
i++;
}
else if (sizesens == 0)
addrsize = 2;
else
addrsize = 4;
}
else if (pd->name[j] == name[i])
i++;
else
break;
};
if (name[i] == '\0' && (pd->name[j] == '\0' || pd->name[j] == ':'))
break; // Bingo!
while (pd->name[j] != '\0' && pd->name[j] != ':')
j++;
if (pd->name[j] == ':')
{
j++;
addrsize = 4;
} // Retry with 32-bit mnenonic
else
{
i = 0;
break; // Comparison failed
};
};
if (i == 0)
continue;
}
// 否则,匹配其他指令助记符
else // Compare with all synonimes
{
j = k = 0;
datasize = 0; // Default settings
addrsize = 4;
// 检测扫描的助记符是否与pd匹配
while (1)
{
// 有些指令有多个助记符,用','号分开
// 例如:JLE,JNG--以逗号分割两个指令
while (pd->name[j] != ',' && pd->name[j] != '\0')
j++;
if (j - k == namelen && strnicmp(name, pd->name + k, namelen) == 0)
break;
// 如果前一助记符不符,则比较后面的助记符是否相符
k = j + 1;
// 已经比较完整个pd指令,则结束本环比较
if (pd->name[j] == '\0')
break;
j = k;
};
if (k > j)
continue;
};
// 至此,说明找到扫描助记符name的pd指令信息
// For error diagnostics错误诊断法 it is important to know whether mnemonic exists.
// 累计找到的pd指令信息
nameok++;
// 统计助记符的操作数个数
// 根据pd指令信息,判断该指令的操作数个数
if (pd->arg1 == NNN || pd->arg1 >= PSEUDOOP)
minop = 0;
// 否则,如果只有1个操作数
else if (pd->arg2 == NNN || pd->arg2 >= PSEUDOOP)
{
if (minop > 1)
minop = 1;
if (maxop < 1)
maxop = 1;
}
// 两个操作数
else if (pd->arg3 == NNN || pd->arg3 >= PSEUDOOP)
{
// 限制其只有两个操作数
if (minop > 2)
minop = 2;
if (maxop < 2)
maxop = 2;
}
// 最多只能有3个操作数
else
maxop = 3;
// Determine default and allowed operand size(s).
// 在汇编语言中,数据长度有两个概念:默认长度与有效长度
// 确定默认和允许的操作数长度
// Forced 16-bit size
// FF:表示强制16位大小
if (pd->bits == FF)
datasize = 2; // Forced 16-bit size
// 检测指令是否只允许使用1字节长度的操作数
// 注:此处的检测逻辑可借鉴指令的编码构造文章
if (pd->bits == WW || pd->bits == WS || pd->bits == W3 || pd->bits == WP)
bytesize = 1; // 1-byte size allowed
else
bytesize = 0; // Word/dword size only
// Check whether command operands match specified. If so, variable match
// remains zero, otherwise it contains kind of mismatch. This allows for
// better error diagnostics错误诊断法.
// 检测命令操作数是否OK,如OK,则match保持为0,否则,包含不匹配的信息
match = 0;
// 检测扫描到的操作数是否OK
for (j = 0; j < 3; j++) // Up to 3 operands
{
// 获取操作数 j
op = aop + j;
// 获取指令pd的操作数类型
if (j == 0)
arg = pd->arg1;
else if (j == 1)
arg = pd->arg2;
else
arg = pd->arg3;
// 如果指令pd没有操作数j
if (arg == NNN || arg >= PSEUDOOP)
{
// 而助记符name却带有该操作数,则出错
if (op->type != NNN) // No more arguments
// 表示助记符操作数个数有误
match |= MA_NOP;
break;
};
// 至此,则说明指令pd有操作数j,但助记符name却没带操作数
if (op->type == NNN)
{
match |= MA_NOP;
break;
}; // No corresponding operand
// 否则,至此,说明带操作数,并且相符,则需要进一步操作了
// 根据所带操作数处理,主要是根据pd操作数检测扫描的助记符操作数是否OK
switch (arg)
{
// 寄存器操作数
case REG: // Integer register in Reg field
case RCM: // Integer register in command byte
// 使用累加器寄存器
case RAC: // Accumulator (AL/AX/EAX, implicit)
// 如果助记符使用的不是寄存器操作数,则类型出错
if (op->type != REG)
match |= MA_TYP;
// 如果pd指令操作数使用累加寄存器(即AL、AX等),而扫描到的助记符使用的
// 操作数寄存器有误,则说明操作数类型有误
if (arg == RAC && op->index != REG_EAX && op->index != 8)
match |= MA_TYP;
// bytesize == 0 -> Word/dword size only
// 如果pd指令只使用word/dword操作数,而助记符却使用byte,则操作数大小出错
if (bytesize == 0 && op->size == 1)
match |= MA_SIZ;
// 如果pd没有指定数据长度,则设置为扫描到的助记符的操作数长度
if (datasize == 0)
datasize = op->size;
// 操作数长度不同
if (datasize != op->size)
match |= MA_DIF;
break;
// 4字节长度的整型寄存器
case RG4: // Integer 4-byte register in Reg field
// 如果助记符操作数不是寄存器,则类型出错
if (op->type != REG)
match |= MA_TYP;
// 如果操作数长度匹配,则出错
if (op->size != 4)
match |= MA_SIZ;
// 保存操作数长度值
if (datasize == 0)
datasize = op->size;
if (datasize != op->size)
match |= MA_DIF;
break;
// AX寄存器,16位
case RAX: // AX (2-byte, implicit)
// 如果扫描到的助记符操作数不是EAX寄存器则出错
if (op->type != REG || (op->index != REG_EAX && op->index != 8))
match |= MA_TYP;
// 不是16位寄存器,即不是AX,则出错
if (op->size != 2)
match |= MA_SIZ;
if (datasize == 0)
datasize = op->size;
if (datasize != op->size)
match |= MA_DIF;
break;
// DX寄存器,一般作为端口地址
case RDX: // DX (16-bit implicit port address)
// 判断同上
if (op->type != REG || (op->index != REG_EDX && op->index != 8))
match |= MA_TYP;
if (op->size != 2)
match |= MA_SIZ;
break;
// CL寄存器,一般作为移位用
case RCL: // Implicit CL register (for shifts)
if (op->type != REG || (op->index != REG_ECX && op->index != 8))
match |= MA_TYP;
if (op->size != 1)
match |= MA_SIZ;
break;
// FPU堆栈顶寄存器
case RS0: // Top of FPU stack (ST(0))
if (op->type != RST || (op->index != 0 && op->index != 8))
match |= MA_TYP;
break;
// FPU堆栈寄存器
case RST: // FPU register (ST(i)) in command byte
if (op->type != RST)
match |= MA_TYP;
break;
// MMX寄存器
case RMX: // MMX register MMx
// 3D寄存器
case R3D: // 3DNow! register MMx
if (op->type != RMX)
match |= MA_TYP;
break;
// 操作数是内存操作数或寄存器操作数,并且该操作数由ModRM提供寻址
// 例如:MOV MRG, REG
case MRG: // Memory/register in ModRM byte
// 如果扫描到的助记符操作数不是MRG,并且也不是寄存器,则出错
if (op->type != MRG && op->type != REG)
match |= MA_TYP;
// 如果操作数只允许使用16位或32位,而扫描到的助记符使用1字节,而长度出错
if (bytesize == 0 && op->size == 1)
match |= MA_SIZ;
if (datasize == 0)
datasize = op->size;
if (op->size != 0 && op->size != datasize)
match |= MA_DIF;
break;
// 同上,操作数由ModRM提供寻址,并且长度为1字节
case MR1: // 1-byte memory/register in ModRM byte
if (op->type != MRG && op->type != REG)
match |= MA_TYP;
if (op->size != 0 && op->size != 1)
match |= MA_SIZ;
break;
// 同上,操作数由ModRM提供寻址,并且长度为2字节
case MR2: // 2-byte memory/register in ModRM byte
if (op->type != MRG && op->type != REG)
match |= MA_TYP;
if (op->size != 0 && op->size != 2)
match |= MA_SIZ;
break;
// 同上,操作数由ModRM提供寻址,并且长度为4字节
case MR4: // 4-byte memory/register in ModRM byte
if (op->type != MRG && op->type != REG)
match |= MA_TYP;
if (op->size != 0 && op->size != 4)
match |= MA_SIZ;
break;
// 操作数是4字节的寄存器
case RR4: // 4-byte memory/register (register only)
if (op->type != REG)
match |= MA_TYP;
if (op->size != 0 && op->size != 4)
match |= MA_SIZ;
break;
// 操作数是JMP的跳转目标地址,并且由ModRM提供寻址
// 例如:CALL MRJ
case MRJ: // Memory/reg in ModRM as JUMP target
if (op->type != MRG && op->type != REG)
match |= MA_TYP;
// 长度必须为4个字节
if (op->size != 0 && op->size != 4)
match |= MA_SIZ;
// Invalid jump size modifier
if ((jmpmode & 0x09) != 0)
match |= MA_JMP;
jmpmode &= 0x7F; // 1111111b
break;
// 对于8字节操作数不关心
case MR8: // 8-byte memory/MMX register in ModRM
case MRD: // 8-byte memory/3DNow! register in ModRM
if (op->type != MRG && op->type != RMX)
match |= MA_TYP;
if (op->size != 0 && op->size != 8)
match |= MA_SIZ;
break;
case RR8: // 8-byte MMX register only in ModRM
case RRD: // 8-byte memory/3DNow! (register only)
if (op->type != RMX)
match |= MA_TYP;
if (op->size != 0 && op->size != 8)
match |= MA_SIZ;
break;
case MMA: // Memory address in ModRM byte for LEA
if (op->type != MRG)
match |= MA_TYP;
break;
case MML: // Memory in ModRM byte (for LES)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 6)
match |= MA_SIZ;
if (datasize == 0)
datasize = 4;
else if (datasize != 4)
match |= MA_DIF;
break;
case MMS: // Memory in ModRM byte (as SEG:OFFS)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 6)
match |= MA_SIZ;
// MA_JMP: Invalid jump size modifier
if ((jmpmode & 0x07) != 0)
match |= MA_JMP;
jmpmode &= 0x7F;
break;
case MM6: // Memory in ModRm (6-byte descriptor)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 6)
match |= MA_SIZ;
break;
case MMB: // Two adjacent memory locations (BOUND)
if (op->type != MRG)
match |= MA_TYP;
k = op->size;
if (ideal == 0 && k > 1)
k /= 2;
if (k != 0 && k != datasize)
match |= MA_DIF;
break;
case MD2: // Memory in ModRM byte (16-bit integer)
case MB2: // Memory in ModRM byte (16-bit binary)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 2)
match |= MA_SIZ;
break;
case MD4: // Memory in ModRM byte (32-bit integer)
case MF4: // Memory in ModRM byte (32-bit float)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 4)
match |= MA_SIZ;
break;
case MD8: // Memory in ModRM byte (64-bit integer)
case MF8: // Memory in ModRM byte (64-bit float)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0 && op->size != 8)
match |= MA_SIZ;
break;
case MDA: // Memory in ModRM byte (80-bit BCD)
case MFA: // Memory in ModRM byte (80-bit float)
if (op->type != MRG)
matc h|= MA_TYP;
if (op->size != 0 && op->size != 10)
match |= MA_SIZ;
break;
case MFE: // Memory in ModRM byte (FPU environment)
case MFS: // Memory in ModRM byte (FPU state)
case MFX: // Memory in ModRM byte (ext. FPU state)
if (op->type != MRG)
match |= MA_TYP;
if (op->size != 0)
match |= MA_SIZ;
break;
case MSO: // Source in string operands ([ESI])
if (op->type != MRG || op->base != REG_ESI || op->index != -1 ||
op->offset != 0 || op->anyoffset != 0)
match |= MA_TYP;
if (datasize == 0)
datasize = op->size;
if (op->size != 0 && op->size != datasize)
match |= MA_DIF;
break;
case MDE: // Destination in string operands ([EDI])
if (op->type != MRG || op->base != REG_EDI || op->index != -1 ||
op->offset != 0 || op->anyoffset != 0)
match |= MA_TYP;
if (op->segment != SEG_UNDEF && op->segment != SEG_ES)
match |= MA_SEG;
if (datasize == 0)
datasize = op->size;
if (op->size != 0 && op->size != datasize)
match |= MA_DIF;
break;
case MXL: // XLAT operand ([EBX+AL])
if (op->type != MXL)
match |= MA_TYP;
break;
// 操作数是一直接数
case IMM: // Immediate data (8 or 16/32)
case IMU: // Immediate unsigned data (8 or 16/32)
if (op->type != IMM)
match |= MA_TYP;
break;
case VXD: // VxD service (32-bit only)
if (op->type != IMM)
match |= MA_TYP;
if (datasize == 0)
datasize = 4;
if (datasize != 4)
match |= MA_SIZ;
break;
// jump/call的直接数地址
case JMF: // Immediate absolute far jump/call addr
if (op->type != JMF)
match |= MA_TYP;
// 地址修饰出错
if ((jmpmode & 0x05) != 0)
match |= MA_JMP;
jmpmode &= 0x7F;
break;
case JOB: // Immediate byte offset (for jumps)
if (op->type != IMM || longjump)
match |= MA_TYP;
if ((jmpmode & 0x0A) != 0)
match |= MA_JMP;
jmpmode &= 0x7F;
break;
case JOW: // Immediate full offset (for jumps)
if (op->type != IMM)
match |= MA_TYP;
if ((jmpmode & 0x09) != 0)
match |= MA_JMP;
jmpmode &= 0x7F;
break;
case IMA: // Immediate absolute near data address
if (op->type != MRG || op->base >= 0 || op->index >= 0)
match |= MA_TYP;
break;
case IMX: // Immediate sign-extendable byte
if (op->type != IMM)
match |= MA_TYP;
if (op->offset < -128 || op->offset > 127)
match |= MA_RNG;
break;
case C01: // Implicit constant 1 (for shifts)
if (op->type != IMM || (op->offset != 1 && op->anyoffset == 0))
match |= MA_TYP;
break;
case IMS: // Immediate byte (for shifts)
case IM1: // Immediate byte
if (op->type != IMM)
match |= MA_TYP;
// 常数范围有误
if (op->offset < -128 || op->offset > 255)
match |= MA_RNG;
break;
case IM2: // Immediate word (ENTER/RET)
if (op->type != IMM)
match |= MA_TYP;
if (op->offset < 0 || op->offset > 65535)
match |= MA_RNG;
break;
// 段寄存器
case SGM: // Segment register in ModRM byte
if (op->type != SGM)
match |= MA_TYP;
if (datasize == 0)
datasize = 2;
if (datasize != 2)
match |= MA_DIF;
break;
//
case SCM: // Segment register in command byte
if (op->type != SGM)
match |= MA_TYP;
break;
// 控制寄存器
case CRX: // Control register CRx
case DRX: // Debug register DRx
if (op->type != arg)
match |= MA_TYP;
if (datasize == 0)
datasize = 4;
if (datasize != 4)
match |= MA_DIF;
break;
case PRN: // Near return address (pseudooperand)
case PRF: // Far return address (pseudooperand)
case PAC: // Accumulator (AL/AX/EAX, pseudooperand)
case PAH: // AH (in LAHF/SAHF, pseudooperand)
case PFL: // Lower byte of flags (pseudooperand)
case PS0: // Top of FPU stack (pseudooperand)
case PS1: // ST(1) (pseudooperand)
case PCX: // CX/ECX (pseudooperand)
case PDI: // EDI (pseudooperand in MMX extentions)
break;
// 错误操作数
default: // Undefined type of operand
strcpy(errtext,"Internal Assembler error");
goto error;
}; // End of switch (arg)
// 在switch(arg)中会对jmpmode进行 & 0x7F的计算,所以其0x80
// 位正常应该为0,所以,如果不为0,则说明出错了
if ((jmpmode & 0x80) != 0)
match |= MA_JMP;
// 如果操作数不匹配,则出错
if (match != 0)
break; // Some of the operands doesn't match
}; // End of operand matching loop
// 如果所有操作数都匹配
if (match == 0) // Exact match found
{
// 允许尝试多次
if (attempt > 0)
{
--attempt;
nameok = 0;
} // Well, try to find yet another match
else
break;
};
}; // End of command search loop : for (pd = cmddata; pd->mask != 0; pd++)
// 至此,对操作数的验证就结束了
// Check whether some error was detected. If several errors were found
// similtaneously, report one (roughly in order of significance).
// 如果助记符无效,则出错
if (nameok == 0) // Mnemonic unavailable
{
strcpy(errtext,"Unrecognized command");
asmcmd = nameend;
goto error;
};
// 操作数不匹配,则出错
if (match != 0) // Command not found
{
if (minop > 0 && aop[minop - 1].type == NNN)
strcpy(errtext, "Too few operands");
else if (maxop < 3 && aop[maxop].type != NNN)
strcpy(errtext, "Too many operands");
// 指令包含了不止一个命令
else if (nameok > 1) // More that 1 command
strcpy(errtext, "Command does not support given operands");
else if (match & MA_JMP)
strcpy(errtext, "Invalid jump size modifier");
else if (match & MA_NOP)
strcpy(errtext, "Wrong number of operands");
else if (match & MA_TYP)
strcpy(errtext, "Command does not support given operands");
else if (match & MA_NOS)
strcpy(errtext, "Please specify operand size");
else if (match & MA_SIZ)
strcpy(errtext, "Bad operand size");
else if (match & MA_DIF)
strcpy(errtext, "Different size of operands");
else if (match & MA_SEG)
strcpy(errtext, "Invalid segment register");
else if (match & MA_RNG)
strcpy(errtext, "Constant out of expected range");
else
strcpy(errtext, "Erroneous command");
goto error;
};
// Exact match found. Now construct the code.
// 至此,命令是OK的,包括操作数,则需要解码该指令了
// 指令是否包含ModR/M字节
hasrm = 0; // Whether command has ModR/M byte
// 指令是否包含SIB字节
hassib = 0; // Whether command has SIB byte
// displacement的长度(如果有)
dispsize = 0; // Size of displacement (if any)
// immediate直接数的长度(如果有)
immsize = 0; // Size of immediate data (if any)
// 指令段前缀
segment = SEG_UNDEF; // Necessary segment prefix
//
jmpsize = 0; // No relative jumps
// tcode:应是用于存储解码后的机器指令,最长指令不超15字节
memset(tcode, 0, sizeof(tcode));
// 获取指令机器码
*(ulong *)tcode = pd->code & pd->mask;
memset(tmask, 0, sizeof(tmask));
*(ulong *)tmask = pd->mask;
// 指令最后字节的编号
// len:指令的长度(不包括操作数),一般为单字节指令
i = pd->len - 1; // Last byte of command itself
// 如果指令包含REP前缀,则长度 + 1
if (rep)
i++; // REPxx prefixes count as extra byte
// 指令w位说明:
// 指令的最低位为w位或最低3位为w
// 当 w = 0 时:operand size 是 byte
// 当 w = 1 时:operand size 是 default operand size
// In some cases at least one operand must have explicit size declaration (as
// in MOV [EAX],1). This preliminary check does not include all cases.
// 在一些情况下,操作数必须明确指定其大小,但并不是所有情况都需要
// 如果是最低位为w位
if (pd->bits == WW || pd->bits == WS || pd->bits == WP)
{
// 如果是 WW || WS || WP,则需要指定操作数大小
if (datasize == 0)
{
strcpy(errtext, "Please specify operand size");
goto error;
}
// 操作数是 word / dword
else if (datasize > 1)
// 置w位为 1,表示操作数大小为 default operand size
tcode[i] |= 0x01; // WORD or DWORD size of operands
// 表示 i 字节将会是操作数长度 [??]
tmask[i] |= 0x01;
}
// 第3位为w位
// Bit W at position 3
else if (pd->bits == W3)
{
if (datasize == 0)
{
strcpy(errtext, "Please specify operand size");
goto error;
}
// 置w位为 1,表示操作数大小为 default operand size
else if (datasize > 1)
tcode[i] |= 0x08; // WORD or DWORD size of operands
tmask[i] |= 0x08;
};
// Present suffix后缀 of 3DNow! command as immediate byte operand.
if ((pd->type & C_TYPEMASK) == C_NOW)
{
immsize = 1;
immediate = (pd->code >> 16) & 0xFF;
};
// Process operands again, this time constructing the code.
// 再次处理操作数,并构建指令
anydisp = anyimm = anyjmp = 0;
for (j = 0; j < 3; j++) // Up to 3 operands
{
// 获取操作数
op = aop + j;
if (j == 0)
arg = pd->arg1;
else if
(j == 1)
arg = pd->arg2;
else
arg = pd->arg3;
// 所有的操作数都处理了,则跳出循环
if (arg == NNN)
break; // All operands processed
// 指令的格式:
// Legacy Prefix + REX prefix + Opcode + ModRM + SIB + Displacement + Immediate
// 根据操作数处理
switch (arg)
{
// 处理寄存器操作数
case REG: // Integer register in Reg field
case RG4: // Integer 4-byte register in Reg field
case RMX: // MMX register MMx
case R3D: // 3DNow! register MMx
case CRX: // Control register CRx
case DRX: // Debug register DRx
// 只要出现寄存器操作数,那么指令就会包含ModRM字节
// 注:ModRM的格式:mod reg r/m
hasrm = 1;
// 指定明确的寄存器作为操作数
if (op->index < 8)
{
// 组织ModRM字节以指明寄存器操作数
tcode[i + 1] |= (char)(op->index << 3);
tmask[i + 1] |= 0x38; // 111000
};
break;
// 整数寄存器或FPU寄存器,则可以将寄存器编码至指令中
// 这种指令使用低3位来指明指令使用的寄存器
case RCM: // Integer register in command byte
case RST: // FPU register (ST(i)) in command byte
//
if (op->index < 8)
{
// 将寄存器号嵌入指令中
tcode[i] |= (char)op->index;
tmask[i] |= 0x07;
};
break;
case RAC: // Accumulator (AL/AX/EAX, implicit)
case RAX: // AX (2-byte, implicit)
case RDX: // DX (16-bit implicit port address)
case RCL: // Implicit CL register (for shifts)
case RS0: // Top of FPU stack (ST(0))
case MDE: // Destination in string op's ([EDI])
case C01: // Implicit constant 1 (for shifts)
break; // Simply skip implicit operands
case MSO: // Source in string op's ([ESI])
case MXL: // XLAT operand ([EBX+AL])
if (op->segment != SEG_UNDEF && op->segment != SEG_DS)
segment = op->segment;
break;
case MRG: // Memory/register in ModRM byte
case MRJ: // Memory/reg in ModRM as JUMP target
case MR1: // 1-byte memory/register in ModRM byte
case MR2: // 2-byte memory/register in ModRM byte
case MR4: // 4-byte memory/register in ModRM byte
case RR4: // 4-byte memory/register (register only)
case MR8: // 8-byte memory/MMX register in ModRM
case RR8: // 8-byte MMX register only in ModRM
case MRD: // 8-byte memory/3DNow! register in ModRM
case RRD: // 8-byte memory/3DNow! (register only)
// 表示存在ModRM字节
hasrm = 1;
// 如果非MRG,则表示是寄存器寻址
if (op->type != MRG) // Register in ModRM byte
{
// 11000000:代表寄存器寻址
tcode[i + 1] |= 0xC0; // 11000000
tmask[i + 1] |= 0xC0;
// 明确指明寄存器,则设置寄存器号
if (op->index < 8)
{
tcode[i + 1] |= (char)op->index;
tmask[i + 1] |= 0x07;
};
break;
}; // Note: NO BREAK, continue with address
// 注意:这里没有break,继续处理地址信息
case MMA: // Memory address in ModRM byte for LEA
case MML: // Memory in ModRM byte (for LES)
case MMS: // Memory in ModRM byte (as SEG:OFFS)
case MM6: // Memory in ModRm (6-byte descriptor)
case MMB: // Two adjacent memory locations (BOUND)
case MD2: // Memory in ModRM byte (16-bit integer)
case MB2: // Memory in ModRM byte (16-bit binary)
case MD4: // Memory in ModRM byte (32-bit integer)
case MD8: // Memory in ModRM byte (64-bit integer)
case MDA: // Memory in ModRM byte (80-bit BCD)
case MF4: // Memory in ModRM byte (32-bit float)
case MF8: // Memory in ModRM byte (64-bit float)
case MFA: // Memory in ModRM byte (80-bit float)
case MFE: // Memory in ModRM byte (FPU environment)
case MFS: // Memory in ModRM byte (FPU state)
case MFX: // Memory in ModRM byte (ext. FPU state)
hasrm = 1;
// 获取操作数的偏移地址
displacement = op->offset;
// 地址中是否存在displacement值
anydisp = op->anyoffset;
// 地址没有包含base与index部分
if (op->base < 0 && op->index < 0)
{
// 则直接数作为地址长度只有32位的情况了
dispsize = 4; // Special case of immediate address
// 如果段前缀使用非默认段(即DS)
if (op->segment != SEG_UNDEF && op->segment != SEG_DS)
segment = op->segment;
// 0x05:101,表示地址为 [disp32]
tcode[i + 1] |= 0x05;
tmask[i + 1] |= 0xC7;
}
// 如果地址没有包含index部分,并且base也不是esp寄存器,则不需要SIB字节来辅助寻址
// 格式:[base + disp]
else if (op->index < 0 && op->base != REG_ESP)
{
// 0xC0:11000000b
tmask[i + 1] |= 0xC0; // SIB byte unnecessary
// 如果未提供offset(即是disp),除非非EBP寄存器,否则是有问题的
if (op->offset == 0 && op->anyoffset == 0 && op->base != REG_EBP)
; // [EBP] always requires offset
else if ((constsize & 1) != 0 && ((op->offset >= -128 && op->offset < 128)
|| op->anyoffset != 0) )
{
// 0x40:1000000b,表示disp为8位数
tcode[i + 1] |= 0x40; // Disp8
dispsize = 1;
}
else
{
// 否则,说明是32位disp数
tcode[i + 1] |= 0x80; // Disp32
dispsize = 4;
};
// 明确指定基址寄存器
if (op->base < 8)
{
// 如果指明操作数的段前缀与该基址的默认段不一致,则使用操作数指明的段作为前缀
if (op->segment != SEG_UNDEF && op->segment != addr32[op->base].defseg)
segment = op->segment;
// 设置操作数的基址
tcode[i + 1] |= (char)op->base; // Note that case [ESP] has base<0.
tmask[i + 1] |= 0x07;
}
// 否则,直接使用操作数指明的段寄存器
else
segment = op->segment;
}
// 地址包含index寄存器部分,则需要SIB寻址
else // SIB byte necessary
{
// 表明指令包含SIB字节
hassib = 1;
// 如果基址使用EBP寄存器,那么需要提供偏移量,所以,如果操作数未提供偏移量
// 而且又提供了index寄存器,并且其scale为1,为了优先,可以将index 寄存器作
// 为基址,而EBP作为index寄存器来使用
if (op->base == REG_EBP && // EBP as base requires offset, optimize
op->index >= 0 && op->scale == 1 && op->offset == 0 && op->anyoffset == 0)
{
op->base = op->index;
op->index = REG_EBP;
};
// ESP寄存器不能作为index使用
if (op->index == REG_ESP && // ESP cannot be an index, reorder
op->scale <= 1)
{
op->index = op->base;
op->base = REG_ESP;
op->scale = 1;
};
// 如果操作数不存在基址,而index寄存器存在,并且scale为2,并且其偏移量为8位,
// 例如[index * 2 + XX],可以优化为:[base + index +XX]
if (op->base < 0 && // No base means 4-byte offset, optimize
op->index >= 0 && op->scale == 2 &&
op->offset >= -128 && op->offset < 128 && op->anyoffset == 0)
{
op->base = op->index;
op->scale = 1;
};
// 至此,如果index还是ESP,则出错
if (op->index == REG_ESP) // Reordering was unsuccessfull
{
strcpy(errtext, "Invalid indexing mode");
goto error;
};
// 确实未指定基址
if (op->base < 0)
{
tcode[i + 1] |= 0x04;
dispsize = 4;
}
// 地址未包含displacement值
else if (op->offset == 0 && op->anyoffset == 0 && op->base != REG_EBP)
tcode[i + 1] |= 0x04; // No displacement
// 包含8位的displacement值
else if ((constsize & 1) != 0 && ((op->offset >= -128 && op->offset < 128)
|| op->anyoffset != 0) )
{
tcode[i + 1] |= 0x44; // Disp8
dispsize = 1;
}
// 包含32位的displacement值
else
{
tcode[i + 1] |= 0x84; // Disp32
dispsize = 4;
}
// 至此,ModRM字节OK了,现在处理SIB字节
tmask[i + 1] |= 0xC7; // ModRM completed, proceed with SIB
// 处理完指令的ModRM,则继续处理SIB字节
if (op->scale == 2)
tcode[i + 2] |= 0x40;
else if (op->scale == 4)
tcode[i + 2] |= 0x80;
else if (op->scale == 8)
tcode[i + 2] |= 0xC0;
tmask[i + 2] |= 0xC0;
// 明确指定index寄存器
if (op->index < 8)
{
// 未指定index
if (op->index < 0)
op->index = 0x04;
// 将index寄存器编码进SIB字节中
tcode[i + 2] |= (char)(op->index << 3);
tmask[i + 2] |= 0x38;
};
// 明确指定base寄存器
if (op->base < 8)
{
if (op->base < 0)
op->base = 0x05;
if (op->segment != SEG_UNDEF && op->segment != addr32[op->base].defseg)
segment = op->segment;
// 将base寄存器编码进SIB字节中
tcode[i + 2] |= (char)op->base;
tmask[i + 2] |= 0x07;
}
else
segment = op->segment;
};
break;
case IMM: // Immediate data (8 or 16/32)
case IMU: // Immediate unsigned data (8 or 16/32)
case VXD: // VxD service (32-bit only)
if (datasize == 0 && pd->arg2 == NNN && (pd->bits == SS || pd->bits == WS))
datasize = 4;
if (datasize == 0)
{
strcpy(errtext, "Please specify operand size");
goto error;
};
immediate = op->offset;
anyimm = op->anyoffset;
if (pd->bits == SS || pd->bits == WS)
{
if (datasize > 1 && (constsize & 2) != 0 && ((immediate >= -128 && immediate < 128)
|| op->anyoffset != 0))
{
immsize = 1;
tcode[i] |= 0x02;
}
else
immsize = datasize;
tmask[i] |= 0x02;
}
else
immsize = datasize;
break;
case IMX: // Immediate sign-extendable byte
case IMS: // Immediate byte (for shifts)
case IM1: // Immediate byte
if (immsize == 2) // To accomodate ENTER instruction
immediate = (immediate & 0xFFFF) | (op->offset << 16);
else
immediate = op->offset;
anyimm |= op->anyoffset;
immsize++;
break;
case IM2: // Immediate word (ENTER/RET)
immediate = op->offset;
anyimm = op->anyoffset;
immsize = 2;
break;
case IMA: // Immediate absolute near data address
if (op->segment != SEG_UNDEF && op->segment != SEG_DS)
segment = op->segment;
displacement = op->offset;
anydisp = op->anyoffset;
dispsize = 4;
break;
case JOB: // Immediate byte offset (for jumps)
jmpoffset = op->offset;
anyjmp = op->anyoffset;
jmpsize = 1;
break;
case JOW: // Immediate full offset (for jumps)
jmpoffset = op->offset;
anyjmp = op->anyoffset;
jmpsize = 4;
break;
case JMF: // Immediate absolute far jump/call addr
displacement = op->offset;
anydisp = op->anyoffset;
dispsize = 4;
immediate = op->segment;
anyimm = op->anyoffset;
immsize = 2;
break;
case SGM: // Segment register in ModRM byte
hasrm = 1;
if (op->index < 6)
{
tcode[i + 1] |= (char)(op->index << 3);
tmask[i + 1] |= 0x38;
};
break;
case SCM: // Segment register in command byte
if (op->index == SEG_FS || op->index == SEG_GS)
{
tcode[0] = 0x0F;
tmask[0] = 0xFF;
i = 1;
if (strcmp(name, "PUSH") == 0)
tcode[i] = (char)((op->index << 3) | 0x80);
else
tcode[i] = (char)((op->index << 3) | 0x81);
tmask[i] = 0xFF;
}
else if (op->index < 6)
{
if (op->index == SEG_CS && strcmp(name, "POP") == 0)
{
strcpy(errtext, "Unable to POP CS");
goto error;
};
tcode[i] = (char)((tcode[i] & 0xC7) | (op->index << 3));
}
else
{
tcode[i] &= 0xC7;
tmask[i] &= 0xC7;
};
break;
case PRN: // Near return address (pseudooperand)
case PRF: // Far return address (pseudooperand)
case PAC: // Accumulator (AL/AX/EAX, pseudooperand)
case PAH: // AH (in LAHF/SAHF, pseudooperand)
case PFL: // Lower byte of flags (pseudooperand)
case PS0: // Top of FPU stack (pseudooperand)
case PS1: // ST(1) (pseudooperand)
case PCX: // CX/ECX (pseudooperand)
case PDI: // EDI (pseudooperand in MMX extentions)
break; // Simply skip preudooperands
default: // Undefined type of operand
strcpy(errtext, "Internal Assembler error");
goto error;
};
};
// 至此,说明指令中对操作数的处理已OK
// Gather parts of command together in the complete command.
j = 0;
// 如果指令包含LOCK前缀
if (lock != 0) // Lock prefix specified
{
// 将LOCK前缀(即0xF0)编入指令中
model->code[j] = 0xF0;
model->mask[j] = 0xFF;
j++;
};
// 如果指令需使用数组长度前缀
if (datasize == 2 && pd->bits != FF) // Data size prefix necessary
{
// 将其编入指令中
model->code[j] = 0x66;
model->mask[j] = 0xFF;
j++;
};
// 同上
if (addrsize == 2) // Address size prefix necessary
{
model->code[j] = 0x67;
model->mask[j] = 0xFF;
j++;
};
// 指定段前缀,将段前缀编码入指令中
if (segment != SEG_UNDEF) // Segment prefix necessary
{
if (segment == SEG_ES)
model->code[j] = 0x26;
else if (segment == SEG_CS)
model->code[j] = 0x2E;
else if (segment == SEG_SS)
model->code[j] = 0x36;
else if (segment == SEG_DS)
model->code[j] = 0x3E;
else if (segment == SEG_FS)
model->code[j] = 0x64;
else if (segment == SEG_GS)
model->code[j] = 0x65;
// 无效的段前缀
else
{
strcpy(errtext, "Internal Assembler error");
goto error;
};
model->mask[j] = 0xFF;
j++;
};
// 如果displacement存在,则同样编码入指令中
if (dispsize > 0)
{
memcpy(tcode + i + 1 + hasrm + hassib, &displacement, dispsize);
if (anydisp == 0)
memset(tmask + i + 1 + hasrm + hassib, 0xFF, dispsize);
};
// 至此,所有的信息足够生成机器指令了
// 指令拥有直接数
if (immsize > 0)
{
if (immsize == 1)
l = 0xFFFFFF00L;
else if (immsize == 2)
l = 0xFFFF0000L;
else
l = 0L;
//
if ((immediate & l) != 0 && (immediate & l) != l)
{
strcpy(errtext, "Constant does not fit into operand");
goto error;
};
memcpy(tcode + i + 1 + hasrm + hassib + dispsize, &immediate, immsize);
if (anyimm == 0)
memset(tmask + i + 1 + hasrm + hassib + dispsize, 0xFF, immsize);
};
i = i + 1 + hasrm + hassib + dispsize + immsize;
jmpoffset = jmpoffset - (i + j + jmpsize);
model->jmpsize = jmpsize;
model->jmpoffset = jmpoffset;
model->jmppos = i + j;
if (jmpsize != 0)
{
if (ip != 0)
{
jmpoffset = jmpoffset - ip;
// 判断跳转范围(有长短两种)
if (jmpsize == 1 && anyjmp == 0 && (jmpoffset < -128 || jmpoffset >= 128))
{
if (longjump == 0 && (jmpmode & 0x03) == 0)
{
longjump = 1;
goto retrylongjump;
};
sprintf(errtext, "Relative jump out of range, use %s LONG form", name);
goto error;
};
memcpy(tcode + i, &jmpoffset, jmpsize);
};
if (anyjmp == 0)
memset(tmask + i, 0xFF, jmpsize);
i += jmpsize;
};
// 将解码后的机器码复制到model中
memcpy(model->code + j, tcode, i);
memcpy(model->mask + j, tmask, i);
i += j;
// 指令长度
model->length = i;
return i; // Positive value: length of code
error:
model->length = 0;
return (int)(cmd - asmcmd); // Negative value: position of error
};
//#pragma option -O. // Restore old optimization options
// ------------------------------------------------- asmserv.cpp -----------------------------------
// assemble.cpp文件中使用到的结构信息
// 文件太长,只摘取一部分
// Free Disassembler and Assembler -- Command data and service routines
//
// Copyright (C) 2001 Oleh Yuschuk
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// 05.03.2002: Corrected error, FSTSW AX assembled with data size prefix
#define STRICT
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <dir.h>
#include <math.h>
#include <float.h>
#pragma hdrstop
#pragma warning(disable:4996)//关闭旧函数声明警告
#include "disasm.h"
/**
* 存储寄存器名称
*
* 类型:低8位寄存器名
* 高8位寄存器名
* 32位寄存器名
*/
const char * regname[3][9] = {
{ "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8" },
{ "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "R16" },
{ "EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI","R32" } };
/**
* 存储段寄存器名称
*/
const char * segname[8] = {
"ES","CS","SS","DS","FS","GS","SEG?","SEG?" };
// 数据长度修饰符
const char * sizename[11] = {
"(0-BYTE)", "BYTE", "WORD", "(3-BYTE)",
"DWORD", "(5-BYTE)", "FWORD", "(7-BYTE)",
"QWORD", "(9-BYTE)", "TBYTE" };
const t_addrdec addr16[8] = {
{ SEG_DS,"BX+SI" }, { SEG_DS,"BX+DI" },
{ SEG_SS,"BP+SI" }, { SEG_SS,"BP+DI" },
{ SEG_DS,"SI" }, { SEG_DS,"DI" },
{ SEG_SS,"BP" }, { SEG_DS,"BX" } };
/**
* 作为地址的两部分:基址与段选择子
* 一般当使用某个寄存器作为基址寄存器时,则会
* 有一个默认的段寄存器作为其选择子用,此数组
* 存储的就是某基址寄存器与相应默认段寄存器的
* 相对信息
*/
const t_addrdec addr32[8] = {
{ SEG_DS,"EAX" }, { SEG_DS,"ECX" },
{ SEG_DS,"EDX" }, { SEG_DS,"EBX" },
{ SEG_SS,"" }, { SEG_SS,"EBP" },
{ SEG_DS,"ESI" }, { SEG_DS,"EDI" } };
// FPU相关寄存器说明:
// 8个80位浮点寄存器(数据),16位状态寄存器,16位控制寄存器,16为标识寄存器。
// 使用FPU指令对这些寄存器进行操作,这些寄存器构成一个循环栈,st7栈底,st0栈顶,
// 当一个值被压入时,被存入st0,原来st0中的值被存入st7
const char * fpuname[9] = {
"ST0","ST1","ST2","ST3","ST4","ST5","ST6","ST7","FPU" };
// MMX寄存器
const char * mmxname[9] = {
"MM0","MM1","MM2","MM3","MM4","MM5","MM6","MM7","MMX" };
// 探制寄存器
const char * crname[9] = {
"CR0","CR1","CR2","CR3","CR4","CR5","CR6","CR7","CRX" };
const char *drname[9] = {
"DR0","DR1","DR2","DR3","DR4","DR5","DR6","DR7","DRX" };
// List of available processor commands with decoding, types of parameters and
// other useful information. Last element has field mask=0. If mnemonic助记符 begins
// with ampersand ('&'), its mnemonic decodes differently depending on operand
// size (16 or 32 bits). If mnemonic begins with dollar ('$'), this mnemonic
// depends on address size. Semicolon (':') separates 16-bit form from 32-bit,
// asterisk ('*') will be substituted by either W (16), D (32) or none (16/32)
// character. If command is of type C_MMX or C_NOW, or if type contains C_EXPL
// (=0x01), Disassembler must specify explicit size of memory operand.
/**
* 存储处理器有效的(机器)指令信息,包括操作数和其他有用信息
*/
const t_cmddata cmddata[] = {
// mask,code,len,bits,arg1,arg2,arg3,type,name
// 指令机器码的获取:code & mask
{ 0x0000FF, 0x000090, 1,00, NNN,NNN,NNN, C_CMD+0, "NOP" },
{ 0x0000FE, 0x00008A, 1,WW, REG,MRG,NNN, C_CMD+0, "MOV" },
{ 0x0000F8, 0x000050, 1,00, RCM,NNN,NNN, C_PSH+0, "PUSH" },
{ 0x0000FE, 0x000088, 1,WW, MRG,REG,NNN, C_CMD+0, "MOV" },
{ 0x0000FF, 0x0000E8, 1,00, JOW,NNN,NNN, C_CAL+0, "CALL" },
{ 0x0000FD, 0x000068, 1,SS, IMM,NNN,NNN, C_PSH+0, "PUSH" },
{ 0x0000FF, 0x000060, 1,00, NNN,NNN,NNN, C_CMD+C_RARE+0, "&PUSHA*" },
{ 0x0038FF, 0x00008F, 1,00, MRG,NNN,NNN, C_POP+1, "POP" },
{ 0x0000FF, 0x000061, 1,00, NNN,NNN,NNN, C_CMD+C_RARE+0, "&POPA*" },
};
// ------------------------------------- disasm.cpp ------------------------------------------
// 用于反编译机器码
// 此文件分析不够详细,但如能看懂assemble.cpp ,则此文件相对简单了很多
// Free Disassembler and Assembler -- Disassembler
//
// Copyright (C) 2001 Oleh Yuschuk
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define STRICT
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <dir.h>
#include <math.h>
#include <float.h>
#pragma hdrstop
#pragma warning(disable:4996)//关闭旧函数声明警告
#include "disasm.h"
//bughoho. 文件扩展名改为cpp.把外部扩展变量在cpp中添加声明
int ideal; // Force IDEAL decoding mode
int lowercase; // Force lowercase display
int tabarguments; // Tab between mnemonic and arguments
int extraspace; // Extra space between arguments
int putdefseg; // Display default segments in listing
int showmemsize; // Always show memory size
int shownear; // Show NEAR modifiers
int shortstringcmds; // Use short form of string commands
// 某些指令助记符中含有'W'或'D'以指明其操作数长度,这种指令的机器码一般依赖于操作数的长度
// 而当这些指令没有指明'W'或'D'时,则根据sizesens决定其操作数长度:
// 0:操作数为16位(字)
// 1:操作数为32位(双字)
int sizesens; // How to decode size-sensitive mnemonics
int symbolic; // Show symbolic addresses in disasm
int farcalls; // Accept far calls, returns & addresses
int decodevxd; // Decode VxD calls (Win95/98)
int privileged; // Accept privileged commands
int iocommand; // Accept I/O commands
int badshift; // Accept shift out of range 1..31
int extraprefix; // Accept superfluous prefixes
int lockedbus; // Accept LOCK prefixes
int stackalign; // Accept unaligned stack operations
int iswindowsnt; // When checking for dangers, assume NT
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// DISASSEMBLER FUNCTIONS ////////////////////////////
// Work variables of disassembler
static ulong datasize; // Size of data (1,2,4 bytes)
// 地址大小
static ulong addrsize; // Size of address (2 or 4 bytes)
static int segprefix; // Segment override prefix or SEG_UNDEF
static int hasrm; // Command has ModR/M byte
// 指令是否包含SIB字节
static int hassib; // Command has SIB byte
// displacement的长度,1表示1字节,2表示2字节
static int dispsize; // Size of displacement (if any)
static int immsize; // Size of immediate data (if any)
static int softerror; // Noncritical disassembler error
// 代码已完成dump的长度
static int ndump; // Current length of command dump
// 登记当前已反汇编的指令长度
static int nresult; // Current length of disassembly
static int addcomment; // Comment value of operand
// Copy of input parameters of function Disasm()
static char *cmd; // Pointer to binary data
static char *pfixup; // Pointer to possible fixups or NULL
static ulong size; // Remaining size of the command buffer
static t_disasm *da; // Pointer to disassembly results
static int mode; // Disassembly mode (DISASM_xxx)
// Disassemble name of 1, 2 or 4-byte general-purpose integer register and, if
// requested and available, dump its contents. Parameter type changes decoding
// of contents for some operand types.
// static void DecodeRG(int index,int datasize,int type)
// bughoho void 改为 int 返回解码得到的寄存器索引
//
static int DecodeRG(int index, int datasize, int type)
{
int sizeindex;
char name[9];
// 无需解码
if (mode < DISASM_DATA)
return -1; // No need to decode
sprintf_s(da->vm_name, "%s_REG%02d", da->vm_name, datasize * 8);
// 操作数类型为寄存器
da->optype[stoperand] = Reg;
// 0x07: 00000111b
index &= 0x07; //得到寄存器索引
if (datasize == 1)
sizeindex = 0;
else if (datasize == 2)
sizeindex = 1;
else if (datasize == 4)
sizeindex = 2;
else
{
da->error = DAE_INTERN;
return -1;
}
// 反汇编
if (mode >= DISASM_FILE)
{
// name中将存储寄存器名称
strcpy(name, regname[sizeindex][index]);
if (lowercase)
strlwr(name);
// 不是一个假操作数
if (type < PSEUDOOP) // Not a pseudooperand
// 将操作数组合至result结果中
nresult += sprintf(da->result + nresult,"%s",name);
// bughoho
if (sizeindex == 0 && (index > 3 && index < 7))
{
// 高8字节寄存器:ah bh ch dh
da->highbit[stoperand] = true;
}
}
// 存储寄存器编号
da->reg[stoperand] = index;
return index;
}
// Disassemble name of 80-bit floating-point register and, if available, dump
// its contents.
// 对index编号的FPU寄存器ST[XX]进行反汇编码
static void DecodeST(int index, int pseudoop)
{
int i;
char s[32];
// 不需反汇编
if (mode < DISASM_FILE)
return; // No need to decode
// 0x07: 00000111b
index &= 0x07;
// s = ST0 | ST1 | ST2 | ...
i = sprintf(s, "%s(%i)", (lowercase ? "st" : "ST"), index);
if (pseudoop == 0)
{
strcpy(da->result + nresult, s);
nresult += i;
}
}
// Disassemble name of 64-bit MMX register.
// 对index编号的MMX寄存器进行反汇编码
static void DecodeMX(int index)
{
char * pr;
if (mode < DISASM_FILE)
return; // No need to decode
index &= 0x07;
pr = da->result + nresult;
nresult += sprintf(pr, "%s%i", (lowercase ? "mm" : "MM"), index);
}
// Disassemble name of 64-bit 3DNow! register and, if available, dump its
// contents.
static void DecodeNR(int index)
{
char * pr;
if (mode < DISASM_FILE)
return; // No need to decode
index &= 0x07;
pr = da->result + nresult;
nresult += sprintf(pr, "%s%i", (lowercase ? "mm" : "MM"), index);
}
// Service function, adds valid memory adress in MASM or Ideal format to
// disassembled string. Parameters: defseg - default segment for given
// register combination, descr - fully decoded register part of address,
// offset - constant part of address, dsize - data size in bytes. If global
// flag 'symbolic' is set, function also tries to decode offset as name of
// some label.
// Memadr(seg, "", addr, dsize);
// defseg: 默认段寄存器
// descr:
// offset:偏址
// dsize: 数据长度
static void Memadr(int defseg, const char *descr,long offset,int dsize)
{
int i, n, seg;
char * pr;
char s[TEXTLEN];
if (mode < DISASM_FILE || descr == NULL)
return; // No need or possibility to decode
char segstr[32] = {0};
if (da->segment != SEG_UNDEF)
{
if (da->segment == SEG_FS)
strcpy(segstr, "FS");
else if (da->segment != SEG_UNDEF && da->segment == SEG_GS)
strcpy(segstr, "GS");
}
sprintf_s(da->vm_name, "%s_%sMEM%02d", da->vm_name, segstr, dsize * 8);
da->optype[stoperand] = Mem;
// 指向反汇编结果缓存区
pr = da->result + nresult;
n = 0;
if (segprefix != SEG_UNDEF)
seg = segprefix;
else
seg = defseg;
if (ideal != 0)
pr[n++] = '[';
// In some cases Disassembler may omit省略 size of memory operand. Namely即是, flag
// showmemsize must be 0, type bit C_EXPL must be 0 (this bit namely means
// that explicit operand size is necessary) and type of command must not be
// C_MMX or C_NOW (because bit C_EXPL has in these cases different meaning).
// Otherwise, exact size must be supplied.
// 如果需要显示内存大小,或是MMX或NOW指令,或C_EXPL设置,则指令不能省略操作数大小
if (showmemsize != 0 || (da->cmdtype & C_TYPEMASK) == C_MMX ||
(da->cmdtype & C_TYPEMASK) == C_NOW || (da->cmdtype & C_EXPL) != 0)
{
if (dsize < sizeof(sizename) / sizeof(sizename[0]))
n += sprintf(pr + n, "%s %s", sizename[dsize], (ideal == 0 ? "PTR " : ""));
else
n += sprintf(pr + n, "(%i-BYTE) %s", dsize, (ideal == 0 ? "PTR " : ""));
}
// BYTE PTR ES: [??]
// putdefseg: Display default segments in listing
// 如果需要显示默认段寄存器,或seg段本身不是默认段,则需要显示
if ((putdefseg != 0 || seg != defseg) && seg != SEG_UNDEF)
n += sprintf(pr + n, "%s:", segname[seg]);
if (ideal == 0)
pr[n++] = '[';
n += sprintf(pr + n, "%s", descr);
if (lowercase)
strlwr(pr);
// 未指定偏移地址
if (offset == 0L)
{
// 并且descr是空字符串,则偏移假设为0
if (*descr == '\0')
pr[n++] = '0';
}
else
{
// symbolic: Show symbolic addresses in disasm
if (symbolic && mode >= DISASM_CODE)
// 空操作,并且返回值为0
i = Decodeaddress(offset, s, TEXTLEN - n - 24, NULL);
else
i = 0;
if (i > 0) // Offset decoded in symbolic form
{
if (*descr != '\0')
pr[n++] = '+';
strcpy(pr + n, s);
n += i;
}
else if (offset < 0 && offset > -16384 && *descr != '\0')
n += sprintf(pr + n, "-%lX", -offset);
else
{
if (*descr != '\0')
pr[n++] = '+';
n += sprintf(pr + n, "%lX", offset);
};
};
pr[n++] = ']';
pr[n] = '\0';
nresult += n;
};
// Disassemble memory/register from the ModRM/SIB bytes and, if available, dump
// address and contents of memory.
static void DecodeMR(int type)
{
int j, memonly, inmemory, seg;
int c, sib;
ulong dsize, regsize, addr;
char s[TEXTLEN];
if (size < 2)
{
da->error = DAE_CROSS;
return;
} // ModR/M byte outside the memory block
hasrm = 1;
// 默认数据大小
dsize = regsize = datasize; // Default size of addressed reg/memory
memonly = 0; // Register in ModM field is allowed
// Size and kind of addressed memory or register in ModM has no influence on对...有影响
// the command size, and exact calculations are omitted if only command size
// is requested. If register is used, optype will be incorrect and we need
// to correct it later.
// 0xC7: 01111100b,取得ModM字节中Mod与M信息
c = cmd[1] & 0xC7; // Leave only Mod and M fields
if (mode >= DISASM_DATA)
{
// 0xC0:11000000b
// 寄存器寻址
if ((c & 0xC0) == 0xC0) // Register operand
inmemory = 0;
else // Memory operand
inmemory = 1;
// 判断是内存操作数还是寄存器操作数, 并确定长度
switch (type)
{
case MRG: // Memory/register in ModRM byte
// 内存操作数
if (inmemory)
{
if (datasize == 1)
da->memtype = DEC_BYTE;
else if (datasize == 2)
da->memtype = DEC_WORD;
else
da->memtype = DEC_DWORD;
}
break;
case MRJ: // Memory/reg in ModRM as JUMP target
if (datasize != 2 && inmemory)
da->memtype = DEC_DWORD;
if (mode >= DISASM_FILE && shownear != 0)
nresult += sprintf(da->result + nresult, "%s ", (lowercase ? "near" : "NEAR"));
break;
case MR1: // 1-byte memory/register in ModRM byte
dsize = regsize = 1;
if (inmemory)
da->memtype = DEC_BYTE;
break;
case MR2: // 2-byte memory/register in ModRM byte
dsize = regsize = 2;
if (inmemory)
da->memtype = DEC_WORD;
break;
case MR4: // 4-byte memory/register in ModRM byte
case RR4: // 4-byte memory/register (register only)
dsize = regsize = 4;
if (inmemory)
da->memtype = DEC_DWORD;
break;
case MR8: // 8-byte memory/MMX register in ModRM
case RR8: // 8-byte MMX register only in ModRM
dsize = 8;
if (inmemory)
da->memtype = DEC_QWORD;
break;
case MRD: // 8-byte memory/3DNow! register in ModRM
case RRD: // 8-byte memory/3DNow! (register only)
dsize = 8;
if (inmemory)
da->memtype = DEC_3DNOW;
break;
case MMA: // Memory address in ModRM byte for LEA
memonly = 1;
break;
case MML: // Memory in ModRM byte (for LES)
dsize = datasize + 2;
memonly = 1;
if (datasize == 4 && inmemory)
da->memtype = DEC_FWORD;
da->warnings |= DAW_SEGMENT;
break;
case MMS: // Memory in ModRM byte (as SEG:OFFS)
dsize = datasize + 2;
memonly = 1;
if (datasize == 4 && inmemory)
da->memtype = DEC_FWORD;
if (mode >= DISASM_FILE)
nresult += sprintf(da->result + nresult, "%s ", (lowercase? "far" : "FAR"));
break;
case MM6: // Memory in ModRM (6-byte descriptor)
dsize = 6;
memonly = 1;
if (inmemory)
da->memtype = DEC_FWORD;
break;
case MMB: // Two adjacent memory locations (BOUND)
dsize = (ideal ? datasize : datasize * 2);
memonly = 1;
break;
case MD2: // Memory in ModRM byte (16-bit integer)
case MB2: // Memory in ModRM byte (16-bit binary)
dsize = 2;
memonly = 1;
if (inmemory)
da->memtype = DEC_WORD;
break;
case MD4: // Memory in ModRM byte (32-bit integer)
dsize = 4;
memonly = 1;
if (inmemory)
da->memtype = DEC_DWORD;
break;
case MD8: // Memory in ModRM byte (64-bit integer)
dsize = 8;
memonly = 1;
if (inmemory)
da->memtype = DEC_QWORD;
break;
case MDA: // Memory in ModRM byte (80-bit BCD)
dsize = 10;
memonly = 1;
if (inmemory)
da->memtype = DEC_TBYTE;
break;
case MF4: // Memory in ModRM byte (32-bit float)
dsize = 4;
memonly = 1;
if (inmemory)
da->memtype = DEC_FLOAT4;
break;
case MF8: // Memory in ModRM byte (64-bit float)
dsize = 8;
memonly = 1;
if (inmemory)
da->memtype = DEC_FLOAT8;
break;
case MFA: // Memory in ModRM byte (80-bit float)
dsize = 10;
memonly = 1;
if (inmemory)
da->memtype = DEC_FLOAT10;
break;
case MFE: // Memory in ModRM byte (FPU environment)
dsize = 28;
memonly = 1;
break;
case MFS: // Memory in ModRM byte (FPU state)
dsize = 108;
memonly = 1;
break;
case MFX: // Memory in ModRM byte (ext. FPU state)
dsize = 512;
memonly = 1;
break;
default: // Operand is not in ModM!
da->error = DAE_INTERN;
break;
};
};
addr = 0;
// There are many possibilities to decode ModM/SIB address. The first
// possibility is register in ModM - general-purpose, MMX or 3DNow!
// 对ModM/SIB地址反汇编有很多种可能。第一种可能就是通用寄存器,MMX或3DNow
// 为0xC0时则是寄存器
if ((c & 0xC0) == 0xC0) // Decode register operand
{
if (type == MR8 || type == RR8)
DecodeMX(c); // MMX register
else if (type == MRD || type == RRD)
DecodeNR(c); // 3DNow! register
// 通用寄存器
else
{
DecodeRG(c, regsize, type); // General-purpose register
}
if (memonly != 0)
softerror = DAE_MEMORY; // Register where only memory allowed
return;
}
// Next possibility: 16-bit addressing mode, very seldom in 32-bit flat model
// but still supported by processor. SIB byte is never used here.
// 下一个可能: 16位地址模式.在32位平坦模式下很少见但是处理器仍然支持
// 这种情况下,SIB字节是不需要用到的
if (addrsize == 2)
{
// 0x06: 110b
// Special case of immediate address
if (c == 0x06)
{
dispsize = 2;
if (size < 4)
da->error = DAE_CROSS; // Disp16 outside the memory block
else if (mode >= DISASM_DATA)
{
// displement值
da->adrconst = addr = *(ushort *)(cmd + 2);
// 该值为0
if (addr == 0)
da->zeroconst = 1;
seg = SEG_DS;
Memadr(seg, "", addr, dsize);
}
}
else
{
da->indexed = 1;
// 0x40: 1000000b
// 8-bit signed displacement
if ((c & 0xC0) == 0x40)
{
if (size < 3)
da->error = DAE_CROSS;
else
addr = (signed char)cmd[2] & 0xFFFF;
dispsize = 1;
}
// 0x80: 10000000b
// 16-bit unsigned displacement
else if ((c & 0xC0) == 0x80)
{
if (size < 4)
da->error = DAE_CROSS;
else
addr = *(ushort *)(cmd + 2);
dispsize = 2;
}
if (mode >= DISASM_DATA && da->error == DAE_NOERR)
{
// 保存地址的displactement部分
da->adrconst = addr;
if (addr == 0)
da->zeroconst = 1;
seg = addr16[c & 0x07].defseg;
Memadr(seg, addr16[c & 0x07].descr, addr, dsize);
}
}
}
// Next possibility: immediate 32-bit address.
// 下一个可能 : 32位立即数的内存地址
// Special case of immediate address
else if (c == 0x05)
{
dispsize = 4;
if (size < 6)
da->error = DAE_CROSS; // Disp32 outside the memory block
else if (mode >= DISASM_DATA)
{
// 设置地址
da->adrconst = addr = *(ulong *)(cmd + 2);
if (pfixup == NULL)
pfixup = cmd + 2;
da->fixupsize += 4;
// 地址为0
if (addr == 0)
da->zeroconst = 1;
// 默认段
seg = SEG_DS;
Memadr(seg, "", addr, dsize);
}
}
// Next possibility: 32-bit address with SIB byte.
// SIB addresation
// 下一个可能:32位地址并且带有SIB字节
else if ((c & 0x07) == 0x04)
{
// 获取SIB字节
sib = cmd[2];
hassib = 1;
*s = '\0';
// [SIB]寻址
if (c == 0x04 && (sib & 0x07) == 0x05)
{
dispsize = 4; // Immediate address without base
if (size < 7)
da->error = DAE_CROSS; // Disp32 outside the memory block
else
{
da->adrconst = addr = *(ulong *)(cmd + 3);
if (pfixup == NULL)
pfixup = cmd + 3;
da->fixupsize += 4;
if (addr == 0)
da->zeroconst = 1;
// Index register present
if ((sib & 0x38) != 0x20)
{
da->indexed = 1;
if (type == MRJ)
da->jmptable = addr;
};
// 默认段寄存器
seg = SEG_DS;
}
}
// Base and, eventually终于,最后, displacement
else
{
// 8-bit displacement
if ((c & 0xC0) == 0x40)
{
dispsize = 1;
if (size < 4)
da->error = DAE_CROSS;
else
{
da->adrconst = addr = (signed char)cmd[3];
if (addr == 0)
da->zeroconst = 1;
}
}
// 32-bit displacement
else if ((c & 0xC0) == 0x80)
{
dispsize = 4;
if (size < 7)
da->error = DAE_CROSS; // Disp32 outside the memory block
else
{
da->adrconst = addr = *(ulong *)(cmd + 3);
if (pfixup == NULL)
pfixup = cmd + 3;
da->fixupsize += 4;
if (addr == 0)
da->zeroconst = 1;
// Most compilers use address of type [index*4+displacement] to
// address jump table (switch). But, for completeness, I allow all
// cases which include index with scale 1 or 4, base or both.
if (type == MRJ)
da->jmptable = addr;
}
}
da->indexed = 1;
j = sib & 0x07;
if (mode >= DISASM_FILE)
{
strcpy(s, regname[2][j]);
seg = addr32[j].defseg;
da->addrreg1 = j;
}
}
// Scaled index present
if ((sib & 0x38) != 0x20)
{
if ((sib & 0xC0) == 0x40)
da->indexed = 2;
else if ((sib & 0xC0) == 0x80)
da->indexed = 4;
else if ((sib & 0xC0) == 0xC0)
da->indexed = 8;
else
da->indexed = 1;
};
if (mode >= DISASM_FILE && da->error == DAE_NOERR)
{
// Scaled index present
if ((sib & 0x38) != 0x20)
{
if (*s != '\0')
strcat(s, "+");
strcat(s, addr32[(sib >> 3) & 0x07].descr);
da->regsscale = 1;
da->addrreg2 = (sib >> 3) & 0x07; // 第2个寄存器偏移
if ((sib & 0xC0) == 0x40)
{
da->jmptable = 0; // Hardly a switch!
strcat(s, "*2");
da->regsscale = 2;
}
else if ((sib & 0xC0) == 0x80)
{
strcat(s, "*4");
da->regsscale = 4;
}
else if ((sib & 0xC0) == 0xC0)
{
da->jmptable = 0; // Hardly a switch!
strcat(s, "*8");
da->regsscale = 8;
}
}
Memadr(seg, s, addr, dsize);
};
}
// Last possibility: 32-bit address without SIB byte.
// 最后一个可能: 32位地址
else // No SIB
{
if ((c & 0xC0) == 0x40)
{
dispsize = 1;
if (size < 3)
da->error = DAE_CROSS; // Disp8 outside the memory block
else
{
da->adrconst = addr = (signed char)cmd[2];
if (addr == 0)
da->zeroconst = 1;
}
}
else if ((c & 0xC0) == 0x80)
{
dispsize = 4;
if (size < 6)
da->error = DAE_CROSS; // Disp32 outside the memory block
else
{
da->adrconst = addr = *(ulong *)(cmd + 2);
if (pfixup == NULL)
pfixup = cmd + 2;
da->fixupsize += 4;
if (addr == 0)
da->zeroconst = 1;
if (type == MRJ)
da->jmptable = addr;
}
}
da->indexed = 1;
if (mode >= DISASM_FILE && da->error == DAE_NOERR)
{
seg = addr32[c & 0x07].defseg;
da->addrreg1 = (c & 0x07);
Memadr(seg, addr32[c & 0x07].descr, addr, dsize);
}
}
}
// Disassemble implicit source of string operations and, if available, dump
// address and contents.
// static void DecodeSO(void)
static int DecodeSO(void)
{
if (mode < DISASM_FILE)
return -1; // No need to decode
if (datasize == 1)
da->memtype = DEC_BYTE;
else if (datasize == 2)
da->memtype = DEC_WORD;
else if (datasize == 4)
da->memtype = DEC_DWORD;
da->indexed = 1;
Memadr(SEG_DS, regname[addrsize == 2 ? 1 : 2][REG_ESI], 0L, datasize);
da->reg[stoperand] = REG_ESI;
return REG_ESI;
}
// Disassemble implicit destination of string operations and, if available,
// dump address and contents. Destination always uses segment ES, and this
// setting cannot be overridden.
//static void DecodeDE(void)
static int DecodeDE(void)
{
int seg;
if (mode<DISASM_FILE)
return -1; // No need to decode
if (datasize==1)
da->memtype=DEC_BYTE;
else if (datasize==2)
da->memtype=DEC_WORD;
else if (datasize==4)
da->memtype=DEC_DWORD;
da->indexed=1;
seg = segprefix;
segprefix=SEG_ES; // Fake Memadr by changing segment prefix
Memadr(SEG_DS,regname[addrsize==2?1:2][REG_EDI],0L,datasize);
segprefix=seg; // Restore segment prefix
da->reg[stoperand] = REG_EDI;
return REG_EDI;
};
// Decode XLAT operand and, if available, dump address and contents.
static void DecodeXL(void)
{
if (mode<DISASM_FILE)
return; // No need to decode
da->memtype=DEC_BYTE;
da->indexed=1;
Memadr(SEG_DS,(addrsize==2?"BX+AL":"EBX+AL"),0L,1);
};
// Decode immediate operand of size constsize. If sxt is non-zero, byte operand
// should be sign-extended to sxt bytes. If type of immediate constant assumes
// this, small negative operands may be displayed as signed negative numbers.
// Note that in most cases immediate operands are not shown in comment window.
static void DecodeIM(int constsize,int sxt,int type)
{
int i;
signed long data;
ulong l;
char name[TEXTLEN],comment[TEXTLEN] = {0};
immsize+=constsize; // Allows several immediate operands
if (mode<DISASM_DATA)
return;
//sprintf_s(da->vm_name,"%s_IMM%02d",da->vm_name,constsize*8);
sprintf_s(da->vm_name,"%s_IMM32",da->vm_name);//IMM只有32位
da->optype[stoperand] = Imm;
l=1+hasrm+hassib+dispsize+(immsize-constsize);
data=0;
if (size<l+constsize)
da->error=DAE_CROSS;
else if (constsize==1)
{
if (sxt==0)
data=(uchar)cmd[l];
else
data=(signed char)cmd[l];
if (type==IMS && ((data & 0xE0)!=0 || data==0))
{
da->warnings|=DAW_SHIFT;
da->cmdtype|=C_RARE;
}
}
else if (constsize==2)
{
if (sxt==0)
data=*(ushort *)(cmd+l);
else
data=*(short *)(cmd+l);
}
else
{
data=*(long *)(cmd+l);
if (pfixup==NULL)
pfixup=cmd+l;
da->fixupsize+=4;
}
if (sxt==2)
data&=0x0000FFFF;
if (data==0 && da->error==0)
da->zeroconst=1;
// Command ENTER, as an exception from Intel's rules, has two immediate
// constants. As the second constant is rarely used, I exclude it from
// search if the first constant is non-zero (which is usually the case).
if (da->immconst==0)
da->immconst=data;
if (mode>=DISASM_FILE && da->error==DAE_NOERR)
{
if (mode>=DISASM_CODE && type!=IMU)
i=Decodeaddress(data,name,TEXTLEN-nresult-24,comment);
else
{
i=0; comment[0]='\0';
}
if (i!=0 && symbolic!=0)
{
strcpy(da->result+nresult,name); nresult+=i;
}
else if (type==IMU || type==IMS || type==IM2 || data>=0 || data<NEGLIMIT)
nresult+=sprintf(da->result+nresult,"%lX",data);
else
nresult+=sprintf(da->result+nresult,"-%lX",-data);
if (addcomment && comment[0]!='\0')
strcpy(da->comment,comment);
}
}
// Decode VxD service name (always 4-byte).
static void DecodeVX(void)
{
ulong l,data;
immsize+=4; // Allows several immediate operands
if (mode<DISASM_DATA)
return;
l=1+hasrm+hassib+dispsize+(immsize-4);
if (size<l+4)
{
da->error=DAE_CROSS;
return;
}
data=*(long *)(cmd+l);
if (data==0 && da->error==0)
da->zeroconst=1;
if (da->immconst==0)
da->immconst=data;
if (mode>=DISASM_FILE && da->error==DAE_NOERR)
{
if ((data & 0x00008000)!=0 && memicmp("VxDCall",da->result,7)==0)
memcpy(da->result,lowercase?"vxdjump":"VxDJump",7);
nresult+=sprintf(da->result+nresult,"%lX",data);
}
}
// Decode implicit constant 1 (used in shift commands). This operand is so
// insignificant that it is never shown in comment window.
static void DecodeC1(void)
{
if (mode<DISASM_DATA)
return;
da->immconst=1;
if (mode>=DISASM_FILE)
nresult+=sprintf(da->result+nresult,"1");
}
// Decode immediate absolute data address. This operand is used in 8080-
// compatible commands which allow to move data from memory to accumulator and
// back. Note that bytes ModRM and SIB never appear in commands with IA operand.
static void DecodeIA(void)
{
ulong addr;
if (size<1+addrsize)
{
da->error=DAE_CROSS;
return;
};
dispsize=addrsize;
if (mode<DISASM_DATA)
return;
if (datasize==1)
da->memtype=DEC_BYTE;
else if (datasize==2)
da->memtype=DEC_WORD;
else if (datasize==4)
da->memtype=DEC_DWORD;
if (addrsize==2)
addr=*(ushort *)(cmd+1);
else
{
addr=*(ulong *)(cmd+1);
if (pfixup==NULL)
pfixup=cmd+1;
da->fixupsize+=4;
}
da->adrconst=addr;
if (addr==0)
da->zeroconst=1;
if (mode>=DISASM_FILE)
{
Memadr(SEG_DS,"",addr,datasize);
}
}
// Decodes jump relative to nextip of size offsize.
static void DecodeRJ(ulong offsize,ulong nextip)
{
sprintf_s(da->vm_name,"%s_IMM%02d",da->vm_name,4*8);//不管长跳短跳都认为是32位地址
da->optype[stoperand] = Imm;
int i;
ulong addr;
char s[TEXTLEN];
if (size<offsize+1)
{
da->error=DAE_CROSS;
return;
}
dispsize=offsize; // Interpret offset as displacement
if (mode<DISASM_DATA)
return;
if (offsize==1)//短跳转
{
addr=(signed char)cmd[1]+nextip;
}
else if (offsize==2)
addr=*(signed short *)(cmd+1)+nextip;
else
addr=*(ulong *)(cmd+1)+nextip;
if (datasize==2)
addr&=0xFFFF;
da->jmpconst=addr;
if (addr==0)
da->zeroconst=1;
if (mode>=DISASM_FILE)
{
if (offsize==1)
nresult+=sprintf(da->result+nresult, "%s ",(lowercase==0?"SHORT":"short"));
if (mode>=DISASM_CODE)
i=Decodeaddress(addr,s,TEXTLEN,da->comment);
else
i=0;
if (symbolic==0 || i==0)
nresult+=sprintf(da->result+nresult,"%08lX",addr);
else
nresult+=sprintf(da->result+nresult,"%.*s",TEXTLEN-nresult-25,s);
if (symbolic==0 && i!=0 && da->comment[0]=='\0')
strcpy(da->comment,s);
}
}
// Decode immediate absolute far jump address. In flat model, such addresses
// are not used (mostly because selector is specified directly in the command),
// so I neither decode as symbol nor comment it. To allow search for selector
// by value, I interprete it as an immediate constant.
static void DecodeJF(void)
{
ulong addr,seg;
if (size<1+addrsize+2)
{
da->error=DAE_CROSS;
return;
}
dispsize=addrsize; immsize=2; // Non-trivial but allowed interpretation
if (mode<DISASM_DATA)
return;
if (addrsize==2)
{
addr=*(ushort *)(cmd+1);
seg=*(ushort *)(cmd+3);
}
else
{
addr=*(ulong *)(cmd+1);
seg=*(ushort *)(cmd+5);
}
da->jmpconst=addr;
da->immconst=seg;
if (addr==0 || seg==0)
da->zeroconst=1;
if (mode>=DISASM_FILE)
{
nresult+=sprintf(da->result+nresult,"%s %04X:%08X",(lowercase==0?"FAR":"far"),seg,addr);
}
}
// Decode segment register. In flat model, operands of this type are seldom.
static void DecodeSG(int index)
{
int i;
if (mode<DISASM_DATA)
return;
index&=0x07;
if (index>=6)
softerror=DAE_BADSEG; // Undefined segment register
sprintf_s(da->vm_name,"%s_%s",da->vm_name,segname[index]);
da->optype[stoperand] = Seg;
if (mode>=DISASM_FILE)
{
da->segreg = index;
i=sprintf(da->result+nresult,"%s",segname[index]);
if (lowercase)
strlwr(da->result+nresult);
nresult+=i;
}
}
// Decode control register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. Contents of control registers are accessible
// only from privilege level 0, so I cannot dump them here.
static void DecodeCR(int index)
{
hasrm=1;
if (mode>=DISASM_FILE)
{
index=(index>>3) & 0x07;
nresult+=sprintf(da->result+nresult,"%s",crname[index]);
if (lowercase)
strlwr(da->result+nresult);
}
}
// Decode debug register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. I can dump only those debug registers
// available in CONTEXT structure.
static void DecodeDR(int index)
{
int i;
hasrm=1;
if (mode>=DISASM_FILE)
{
index=(index>>3) & 0x07;
i=sprintf(da->result+nresult,"%s",drname[index]);
if (lowercase)
strlwr(da->result+nresult);
nresult+=i;
}
}
// Skips 3DNow! operands and extracts command suffix. Returns suffix or -1 if
// suffix lies outside the memory block. This subroutine assumes that cmd still
// points to the beginning of 3DNow! command (i.e. to the sequence of two bytes
// 0F, 0F).
/**
* 获取3dNow指令的后缀,对于什么是其后缀,可上网搜索
*
* 3dNow指令格式:0Fh 0Fh modR/M [sib] [displacement] 3DNow!_suffix
*
* 返回值:成功返回其后缀,否则返回-1
*/
static int Get3dnowsuffix(void)
{
int c, sib;
ulong offset;
// 如果3dNow后缀超出内存块
if (size < 3)
return -1; // Suffix outside the memory block
// 3dNow指令的后缀偏移
offset = 3;
// ModRM 字节的组成部分为:mod-reg-r/m
// 0xC7: 11000111b
c = cmd[2] & 0xC7; // Leave only Mod and M fields
// Register in ModM - general-purpose多方面的,多用途的, MMX or 3DNow!
// 0xC0: 11000000b
// 高两位为1,表示寄存器寻址
if ((c & 0xC0) == 0xC0)
;
// 16-bit addressing mode, SIB byte is never used here.
// 否则,如果是16位地址模式,则SIB不会被使用
else if (addrsize == 2)
{
if (c == 0x06) // Special case of immediate address
offset += 2;
// 0x40: 1000000b
else if ((c & 0xC0) == 0x40) // 8-bit signed displacement
offset++;
// 0x80: 10000000b
else if ((c & 0xC0) == 0x80) // 16-bit unsigned displacement
offset += 2;
}
// Immediate 32-bit address.
// 0x05: 101b
else if (c == 0x05) // Special case of immediate address
offset += 4;
// 32-bit address with SIB byte.
// 如果指令使用32位地址模式并带有SIB字节
else if ((c & 0x07) == 0x04) // SIB addresation
{
if (size < 4)
return -1; // Suffix outside the memory block
// 获取SIB字节
sib = cmd[3];
offset++;
if (c == 0x04 && (sib & 0x07) == 0x05)
offset += 4; // Immediate address without base
else if ((c & 0xC0) == 0x40) // 8-bit displacement
offset += 1;
else if ((c & 0xC0) == 0x80) // 32-bit dislacement
offset += 4;
}
// 32-bit address without SIB byte
else if ((c & 0xC0) == 0x40)
offset += 1;
else if ((c & 0xC0) == 0x80)
offset += 4;
if (offset >= size)
return -1; // Suffix outside the memory block
return cmd[offset];
}
// Function checks whether 80x86 flags meet condition set in the command.
// Returns 1 if condition is met, 0 if not and -1 in case of error (which is
// not possible).
int Checkcondition(int code,ulong flags)
{
ulong cond,temp;
switch (code & 0x0E)
{
case 0: // If overflow
cond=flags & 0x0800;
break;
case 2: // If below
cond=flags & 0x0001;
break;
case 4: // If equal
cond=flags & 0x0040;
break;
case 6: // If below or equal
cond=flags & 0x0041;
break;
case 8: // If sign
cond=flags & 0x0080;
break;
case 10: // If parity
cond=flags & 0x0004;
break;
case 12: // If less
temp=flags & 0x0880;
cond=(temp==0x0800 || temp==0x0080);
break;
case 14: // If less or equal
temp=flags & 0x0880;
cond=(temp==0x0800 || temp==0x0080 || (flags & 0x0040)!=0);
break;
default:
return -1; // Internal error, not possible!
}
if ((code & 0x01)==0)
return (cond!=0);
else
return (cond==0); // Invert condition
}
// bughoho
int stoperand = 0;
// Disasm(base_addr, MAXCMDSIZE, VirtualAddress, &da, DISASM_CODE)
ulong Disasm(char * src, ulong srcsize, ulong srcip, t_disasm * disasm, int disasmmode)
{
// isprefix: 表示指令是否有段前缀,加锁总线前缀等前缀
// is3dnow: 表示指令是否是3dNow指令
int i, j, isprefix, is3dnow, repeated, operand, mnemosize, arg = 0;
ulong u, code;
// 是否存在LOCK前缀
int lockprefix; // Non-zero if lock prefix present
// 是否存在REP前缀
int repprefix; // REPxxx prefix or 0
int cxsize;
// pname: 保存前缀名称,如REPN、REPE
char name[TEXTLEN], * pname;
const t_cmddata * pd, * pdan;
// Prepare disassembler variables and initialize structure disasm.
// 初始化结构和变量
datasize = addrsize = 4; // 32-bit code and data segments only!
// 指令的段前缀
segprefix = SEG_UNDEF;
hasrm = hassib=0;
dispsize = immsize = 0;
// 加锁总线前缀
lockprefix = 0;
// REP前缀
repprefix = 0;
ndump = 0;
nresult = 0;
// 指令
cmd = src;
size = srcsize;
pfixup = NULL;
softerror = 0;
is3dnow = 0;
da = disasm;
da->ip = srcip;
da->comment[0] = '\0';
da->cmdtype = C_BAD;
da->nprefix = 0;
da->memtype = DEC_UNKNOWN;
da->indexed = 0;
da->jmpconst = 0;
da->jmptable = 0;
da->adrconst = 0;
da->immconst = 0;
da->zeroconst = 0;
da->fixupoffset = 0;
da->fixupsize = 0;
da->warnings = 0;
da->error = DAE_NOERR;
mode = disasmmode; // No need to use register contents
// 操作数类型
da->optype[0] = da->optype[1] = da->optype[2] = -1;
// 3个寄存器,当操作数为寄存器时
da->reg[0] = da->reg[1] = da->reg[2] = -1;
// 段寄存器
da->segreg = -1;
da->addrreg1 = da->addrreg2 = -1;
da->regsscale = 1;
// 清二进制代码
memset(da->hexcode, 0, TEXTLEN);
da->codelen = 0;
da->highbit[0] = da->highbit[1] = da->highbit[2] = false;
// Correct 80x86 command may theoretically在理论上 contain up to多达 4 prefixes belonging
// to different prefix groups. This limits maximal possible size of the
// command to MAXCMDSIZE=16 bytes. In order to maintain this limit, if
// Disasm() detects second prefix from the same group, it flushes first
// prefix in the sequence顺序 as a pseudocommand伪指令.
u = 0;
repeated = 0;
// 统计指令cmd中所有的前缀数
while (size > 0)
{
// 假设存在一些前缀
isprefix = 1; // Assume that there is some prefix
// 根据指令处理其前缀部分
switch (* cmd)
{
// 段前缀
case 0x26:
if (segprefix == SEG_UNDEF)
segprefix = SEG_ES;
else
// 重复出现0x26
repeated = 1;
break;
case 0x2E:
if (segprefix == SEG_UNDEF)
segprefix = SEG_CS;
else
repeated = 1;
break;
case 0x36:
if (segprefix == SEG_UNDEF)
segprefix = SEG_SS;
else
repeated = 1;
break;
case 0x3E:
if (segprefix == SEG_UNDEF)
segprefix = SEG_DS;
else
repeated = 1;
break;
case 0x64:
if (segprefix == SEG_UNDEF)
segprefix = SEG_FS;
else
repeated = 1;
break;
case 0x65:
if (segprefix == SEG_UNDEF)
segprefix = SEG_GS;
else
repeated = 1;
break;
// 66H前缀用来更改operands size,当然只能在指令所
// 支持的 effective operand-size 范围内进行调整
case 0x66:
if (datasize == 4)
datasize = 2;
else
// 前缀重复
repeated = 1;
break;
// 指令中可以 67H 进行 address size override
case 0x67:
if (addrsize == 4)
addrsize = 2;
else
repeated = 1;
break;
// 加锁总线前缀
case 0xF0:
if (lockprefix == 0)
lockprefix = 0xF0;
else
repeated = 1;
break;
// REP前缀
case 0xF2:
if (repprefix == 0)
repprefix = 0xF2;
else
repeated = 1;
break;
case 0xF3:
if (repprefix == 0)
repprefix = 0xF3;
else
repeated = 1;
break;
default:
isprefix = 0;
break;
}
// 如果没有前缀,或前缀重复,则跳出循环
if (isprefix == 0 || repeated != 0)
break; // No more prefixes or duplicated prefix
if (mode >= DISASM_FILE)
{
ndump += sprintf(da->dump + ndump, "%02X:", * cmd);
da->hexcode[da->codelen++] = *cmd;
}
// 累计指令前缀数
da->nprefix++;
cmd++;
srcip++;
size--;
u++;
}
// bughoho
da->segment = segprefix; // 得到段寄存器
// We do have repeated prefix. Flush first prefix from the sequence.
// 如果指令拥有重复的前缀
if (repeated)
{
// 如果是对代码进行反汇编 [??]
if (mode >= DISASM_FILE)
{
da->dump[3] = '\0'; // Leave only first dumped prefix
// 为何只保留一个前缀
da->nprefix = 1;
// 获取前缀的名称
switch (cmd[-(long)u]) // cmd++ 且 u++;这里是得到cmd[0]
{
case 0x26: pname = (char *)(segname[SEG_ES]);
break;
case 0x2E: pname = (char *)(segname[SEG_CS]);
break;
case 0x36: pname = (char *)(segname[SEG_SS]);
break;
case 0x3E: pname = (char *)(segname[SEG_DS]);
break;
case 0x64: pname = (char *)(segname[SEG_FS]);
break;
case 0x65: pname = (char *)(segname[SEG_GS]);
break;
case 0x66: pname = "DATASIZE";
break;
case 0x67: pname = "ADDRSIZE";
break;
case 0xF0: pname = "LOCK";
break;
case 0xF2: pname = "REPNE";
break;
case 0xF3: pname = "REPE";
break;
default: pname = "?";
break;
}
// 累计已反汇编的指令长度
nresult += sprintf(da->result + nresult, "PREFIX %s:",pname);
// 是否强制要求以小写显示
if (lowercase)
strlwr(da->result);
// 不支持扩展的前缀(多余的前缀)
if (extraprefix == 0)
strcpy(da->comment, "Superfluous prefix");
}
// 警告:指令有过多的前缀
da->warnings |= DAW_PREFIX;
// 指令存在加锁总线的前缀
if (lockprefix)
da->warnings |= DAW_LOCK;
// 该指令罕见,少用
da->cmdtype = C_RARE;
return 1; // Any prefix is 1 byte long
}
// If lock prefix available, display it and forget, because it has no
// influence on对...有影响 decoding of rest of the command.
// 指令存在加锁总线的前缀
if (lockprefix != 0)
{
if (mode >= DISASM_FILE)
nresult += sprintf(da->result + nresult, "LOCK ");
da->warnings |= DAW_LOCK;
}
// Fetch (if available) first 3 bytes of the command, add repeat prefix and
// find command in the command table.
// 取得命令的前三个字节
code = 0;
// 如果指令剩余空间存在
if (size > 0)
*(((char *)&code) + 0) = cmd[0];
if (size > 1)
*(((char *)&code) + 1) = cmd[1];
if (size > 2)
*(((char *)&code) + 2) = cmd[2];
// 如果REP前缀存在
if (repprefix != 0) // RER/REPE/REPNE is considered to be
// 则将其加入到code指令中
code = (code << 8) | repprefix; // part of command.
if (decodevxd && (code & 0xFFFF) == 0x20CD)
pd = &vxdcmd; // Decode VxD call (Win95/98)
else
{
// 遍历指令表
for (pd = cmddata; pd->mask != 0; pd++)
{
// 检测是否pd指令
if (((code ^ pd->code) & pd->mask) != 0)
continue;
// 如果是反汇编模式,并且Use short form of string commands
if (mode >= DISASM_FILE && shortstringcmds &&
// 如果寄存器是ESI或EDI
(pd->arg1 == MSO || pd->arg1 == MDE || pd->arg2 == MSO || pd->arg2 == MDE))
continue; // Search short form of string command
break;
}
}
if ( (pd->type & C_TYPEMASK) == C_NOW) // 如果是3DNow指令
{
// 3DNow! commands require additional search.
is3dnow = 1;
// 获取3DNow指令的后缀
j = Get3dnowsuffix();
// 当存放指令的内存空间不足时,会返回-1
// 这表示指令与内存交叉,出错
if (j < 0)
da->error = DAE_CROSS;
else
{
// 遍历指令表,获取后缀与欲反汇编指令相匹配的指令
for ( ; pd->mask != 0; pd++)
{
if (((code ^ pd->code) & pd->mask) != 0)
continue;
if (((uchar *)&(pd->code))[2] == j)
break;
}
}
}
// bughoho
da->is3dnow = is3dnow; // 是否是3DNow!指令
// Command not found
if (pd->mask == 0) // 命令未找到
{
// 指令错误
da->cmdtype = C_BAD;
if (size < 2)
da->error = DAE_CROSS;
else
da->error = DAE_BADCMD;
}
// 指令OK,是一注册指令,则反汇编之
else
{
// Command recognized, decode it
// 指令类型信息
da->cmdtype = pd->type;
// ECX作为记数寄存器的默认长度,与数据长度等同
cxsize = datasize; // Default size of ECX used as counter
// 如果段前缀是FS 或 GS 或存在 LOCK 前缀
// 则表明此指令并不常用
if (segprefix == SEG_FS || segprefix == SEG_GS || lockprefix != 0)
da->cmdtype |= C_RARE; // These prefixes are rare
// 如果该指令是一个特权指令
if (pd->bits == PR)
da->warnings |= DAW_PRIV; // Privileged command (ring 0)
// IO命令
else if (pd->bits == WP)
da->warnings |= DAW_IO; // I/O command
// Win32 programs usually try to keep stack dword-aligned, so INC ESP
// (44) and DEC ESP (4C) usually don't appear in real code. Also check for
// ADD ESP,imm and SUB ESP,imm (81,C4,imm32; 83,C4,imm8; 81,EC,imm32;
// 83,EC,imm8).
// WIN32程序通常会保持栈的双字对齐, 所以inc esp,dec esp一般不会出现在
// 平常的代码中, 除此同样检测add esp,imm 和 sub esp,imm.
if (cmd[0] == 0x44 || cmd[0] == 0x4C ||
(size >= 3 && (cmd[0] == 0x81 || cmd[0] == 0x83) &&
(cmd[1] == 0xC4 || cmd[1] == 0xEC) && (cmd[2] & 0x03) != 0))
{
da->warnings |= DAW_STACK; // 栈对齐警告
da->cmdtype |= C_RARE; // 不常出现的指令
}
// Warn also on MOV SEG,... (8E...). Win32 works in flat mode.
// 警告mov seg,xxx 操作, 因为Win32工作在平坦模式
if (cmd[0] == 0x8E)
da->warnings |= DAW_SEGMENT;
// If opcode is 2-byte, adjust command.
// 如果操作码是2字节的则调整命令
if (pd->len == 2)
{
if (size == 0)
da->error = DAE_CROSS;
else
{
// 工作于反汇编模式
if (mode >= DISASM_FILE)
{
// 将原二进制代码dump至da->dump中
ndump += sprintf(da->dump + ndump, "%02X", *cmd);
// 存储二进制代码
da->hexcode[da->codelen++] = *cmd;
}
cmd++;
srcip++;
size--;
}
}
if (size == 0)
da->error = DAE_CROSS;
// Some commands either feature non-standard data size or have bit which
// allowes to select data size.
// 一些命令的数据长度不是标准的,其长度是可变的
if ((pd->bits & WW) != 0 && (*cmd & WW) == 0)
datasize = 1; // Bit W in command set to 0
else if ((pd->bits & W3) != 0 && (*cmd & W3) == 0)
datasize = 1; // Another position of bit W
else if ((pd->bits & FF) != 0)
datasize = 2; // Forced word (2-byte) size
// Some commands either have mnemonics which depend on data size (8/16 bits
// or 32 bits, like CWD/CDQ), or have several different mnemonics (like
// JNZ/JNE). First case is marked by either '&' (mnemonic depends on
// operand size) or '$' (depends on address size). In the second case,
// there is no special marker and disassembler selects main mnemonic.
// 有些指令的助记符依赖于数据长度(例如CWD/CDQ),或拥有多个不同的助记符
// (例如JNZ/JNE)。第一种情况是使用"&"或"$"标记。第二种情况没有特定标记
// 并被反汇编为主要的助记符
if (mode >= DISASM_FILE)
{
// 指令的助记符依赖于操作数大小
if (pd->name[0] == '&')
mnemosize = datasize;
// 指令的助记符依赖于地址大小
else if (pd->name[0] == '$')
mnemosize = addrsize;
else
mnemosize = 0;
// 助记符大小不为0,依赖数据或地址大小
if (mnemosize != 0)
{
// 遍历pd指令的符号名中每个字符
for (i = 0,j = 1; pd->name[j] != '\0'; j++)
{
// 如果不是":"分割符
if (pd->name[j] == ':')
{
// Separator between 16/32 mnemonics
// 分割符用于分割16位/32位的助记符
if (mnemosize == 4)
i = 0;
else
break;
}
// 指令中如出现"*",则用"W"或"D"代替,作为其长度标记
else if (pd->name[j] == '*')
{
// Substitute替换,代替 by 'W', 'D' or none
if (mnemosize == 4 && sizesens != 2)
name[i++] = 'D';
else if (mnemosize != 4 && sizesens != 0)
name[i++] = 'W';
}
else
name[i++] = pd->name[j];
}
name[i] = '\0';
}
// 否则,说明指令不依赖数据或地址大小
else
{
strcpy(name, pd->name);
// 当指令中有","号分割时,说明该指令有多个
// 助记符,使用主要的一个就行
for (i = 0; name[i] != '\0'; i++)
{
if (name[i] == ',')
{
// Use main mnemonic
name[i] = '\0';
break;
}
}
}
// 将name反汇编后的指令复制至da中
// 存在REP前缀,并且...
if (repprefix != 0 && tabarguments)
{
for (i = 0; name[i] != '\0' && name[i] != ' '; i++)
da->result[nresult++] = name[i];
if (name[i] == ' ')
{
da->result[nresult++] = ' ';
i++;
}
while(nresult < 8)
da->result[nresult++] = ' ';
for ( ; name[i] != '\0'; i++)
da->result[nresult++] = name[i];
}
else
nresult += sprintf(da->result + nresult, "%s", name);
// 要求指令转小写
if (lowercase)
strlwr(da->result);
sprintf_s(da->vm_name, "V%s", name);
}
// Decode operands (explicit - encoded in command, implicit - present in
// mmemonic or assumed - used or modified by command). Assumed operands
// must stay after all explicit and implicit operands. Up to 3 operands
// are allowed.
// 处理操作数,最多可以有3个
for (operand = 0; operand < 3; operand++)
{
stoperand = operand;
// 如果已出错,则直接跳出,不需继续了
if (da->error)
break; // Error - no sense to continue
// If command contains both source and destination, one usually must not
// decode destination to comment because it will be overwritten on the
// next step. Global addcomment takes care of this. Decoding routines,
// however, may ignore this flag.
if (operand == 0 && pd->arg2 != NNN && pd->arg2 < PSEUDOOP)
addcomment = 0;
else
addcomment = 1;
// Get type of next argument.
if (operand == 0)
arg = pd->arg1;
else if (operand == 1)
arg = pd->arg2;
else
arg = pd->arg3;
// 没有更多的操作数了
if (arg == NNN)
break; // No more operands
// Arguments with arg>=PSEUDOOP are assumed operands and are not
// displayed in disassembled result, so they require no delimiter.
// 参数>=PSEUDOOP是假的操作数,并且不显示在反汇编的结果中,所以
// 他们不需要分割符
if ((mode >= DISASM_FILE) && arg < PSEUDOOP) // 添加间隔
{
// 指令与第1个操作数之前有 ' ' 间隔
if (operand == 0)
{
da->result[nresult++] = ' ';
if (tabarguments)
{
while (nresult < 8)
da->result[nresult++] = ' ';
}
}
// 操作数之间则以 ',' 间隔
else
{
da->result[nresult++] = ',';
if (extraspace)
da->result[nresult++] = ' ';
}
}
// Decode, analyse and comment next operand of the command.
// 解码,分析和注释命令的下一个操作数
// 现在正式开始
switch (arg)
{
// 参数是整型寄存器
case REG: // Integer register in Reg field
if (size < 2)
da->error = DAE_CROSS;
else
{
DecodeRG(cmd[1] >> 3, datasize, REG);
}
// 表示指令含有ModRm字节
hasrm = 1;
break;
// 参数是整型寄存器,并嵌入指令中
case RCM: // Integer register in command byte
// 注意:此处下标为0
DecodeRG(cmd[0], datasize, RCM);
break;
// 4字节长度整型寄存器
case RG4: // Integer 4-byte register in Reg field
if (size < 2)
da->error = DAE_CROSS;
else
{
DecodeRG(cmd[1] >> 3, 4, RG4);
}
hasrm = 1;
break;
// 累加器寄存器
case RAC: // Accumulator (AL/AX/EAX, implicit)
DecodeRG(REG_EAX, datasize, RAC);
break;
// AX寄存器
case RAX: // AX (2-byte, implicit)
DecodeRG(REG_EAX, 2, RAX);
break;
// DX寄存器,16位端口地址
case RDX: // DX (16-bit implicit port address)
DecodeRG(REG_EDX, 2, RDX);
break;
// CL寄存器,用于移位
case RCL: // Implicit CL register (for shifts)
DecodeRG(REG_ECX, 1, RCL);
break;
// FPU堆顶寄存器
case RS0: // Top of FPU stack (ST(0))
DecodeST(0, 0);
break;
// FPU寄存器
case RST: // FPU register (ST(i)) in command byte
DecodeST(cmd[0], 0);
break;
// MMX寄存器
case RMX: // MMX register MMx
if (size < 2)
da->error = DAE_CROSS;
else
DecodeMX(cmd[1] >> 3);
hasrm = 1;
break;
// 3DNow寄存器
case R3D: // 3DNow! register MMx
if (size < 2)
da->error = DAE_CROSS;
else
DecodeNR(cmd[1] >> 3);
hasrm = 1;
break;
case MRG: // Memory/register in ModRM byte
case MRJ: // Memory/reg in ModRM as JUMP target
case MR1: // 1-byte memory/register in ModRM byte
case MR2: // 2-byte memory/register in ModRM byte
case MR4: // 4-byte memory/register in ModRM byte
case MR8: // 8-byte memory/MMX register in ModRM
case MRD: // 8-byte memory/3DNow! register in ModRM
case MMA: // Memory address in ModRM byte for LEA
case MML: // Memory in ModRM byte (for LES)
case MM6: // Memory in ModRm (6-byte descriptor)
case MMB: // Two adjacent memory locations (BOUND)
case MD2: // Memory in ModRM byte (16-bit integer)
case MB2: // Memory in ModRM byte (16-bit binary)
case MD4: // Memory in ModRM byte (32-bit integer)
case MD8: // Memory in ModRM byte (64-bit integer)
case MDA: // Memory in ModRM byte (80-bit BCD)
case MF4: // Memory in ModRM byte (32-bit float)
case MF8: // Memory in ModRM byte (64-bit float)
case MFA: // Memory in ModRM byte (80-bit float)
case MFE: // Memory in ModRM byte (FPU environment)
case MFS: // Memory in ModRM byte (FPU state)
case MFX: // Memory in ModRM byte (ext. FPU state)
DecodeMR(arg);
break;
case MMS: // Memory in ModRM byte (as SEG:OFFS)
DecodeMR(arg);
da->warnings |= DAW_FARADDR;
break;
case RR4: // 4-byte memory/register (register only)
case RR8: // 8-byte MMX register only in ModRM
case RRD: // 8-byte memory/3DNow! (register only)
if ((cmd[1] & 0xC0)!=0xC0)
softerror=DAE_REGISTER;
DecodeMR(arg);
break;
case MSO: // Source in string op's ([ESI])
DecodeSO();
break;
case MDE: // Destination in string op's ([EDI])
DecodeDE();
break;
case MXL: // XLAT operand ([EBX+AL])
DecodeXL();
break;
case IMM: // Immediate data (8 or 16/32)
case IMU: // Immediate unsigned data (8 or 16/32)
if ((pd->bits & SS)!=0 && (*cmd & 0x02)!=0)
DecodeIM(1,datasize,arg);
else
DecodeIM(datasize,0,arg);
break;
case VXD: // VxD service (32-bit only)
DecodeVX();//未解决
break;
case IMX: // Immediate sign-extendable byte
DecodeIM(1,datasize,arg);
break;
case C01: // Implicit constant 1 (for shifts)
DecodeC1();//未解决
break;
case IMS: // Immediate byte (for shifts)
case IM1: // Immediate byte
DecodeIM(1,0,arg);
break;
case IM2: // Immediate word (ENTER/RET)
DecodeIM(2,0,arg);
if ((da->immconst & 0x03)!=0)
da->warnings|=DAW_STACK;
break;
case IMA: // Immediate absolute near data address
DecodeIA(); //[imm] ok
break;
case JOB: // Immediate byte offset (for jumps)
DecodeRJ(1,srcip+2);//无须解决jmpconst则是
break;
case JOW: // Immediate full offset (for jumps)
DecodeRJ(datasize,srcip+datasize+1);//无须解决jmpconst则是
break;
case JMF: // Immediate absolute far jump/call addr
DecodeJF();//未解决
da->warnings|=DAW_FARADDR;
break;
case SGM: // Segment register in ModRM byte
if (size<2)
da->error=DAE_CROSS;
DecodeSG(cmd[1]>>3);
hasrm=1;
break;
case SCM: // Segment register in command byte
DecodeSG(cmd[0]>>3);
if ((da->cmdtype & C_TYPEMASK)==C_POP)
da->warnings|=DAW_SEGMENT;
break;
case CRX: // Control register CRx
if ((cmd[1] & 0xC0)!=0xC0)
da->error=DAE_REGISTER;
DecodeCR(cmd[1]);//未解决
break;
case DRX: // Debug register DRx
if ((cmd[1] & 0xC0)!=0xC0)
da->error=DAE_REGISTER;
DecodeDR(cmd[1]);//未解决
break;
case PRN: // Near return address (pseudooperand)
break;
case PRF: // Far return address (pseudooperand)
da->warnings|=DAW_FARADDR;
break;
case PAC: // Accumulator (AL/AX/EAX, pseudooperand)
DecodeRG(REG_EAX,datasize,PAC);
break;
case PAH: // AH (in LAHF/SAHF, pseudooperand)
case PFL: // Lower byte of flags (pseudooperand)
break;
case PS0: // Top of FPU stack (pseudooperand)
DecodeST(0,1);//未解决
break;
case PS1: // ST(1) (pseudooperand)
DecodeST(1,1);//未解决
break;
case PCX: // CX/ECX (pseudooperand)
DecodeRG(REG_ECX,cxsize,PCX);
break;
case PDI: // EDI (pseudooperand in MMX extentions)
DecodeRG(REG_EDI,4,PDI);
break;
default:
da->error=DAE_INTERN; // Unknown argument type
break;
}
da->memsize[operand] = datasize;
}
// Check whether command may possibly contain fixups.
if (pfixup != NULL && da->fixupsize > 0)
da->fixupoffset = (int)(pfixup - src);
// Segment prefix and address size prefix are superfluous for command which
// does not access memory. If this the case, mark command as rare to help
// in analysis.
// 段前缀与地址大小前缀过多
if (da->memtype == DEC_UNKNOWN &&
(segprefix != SEG_UNDEF || (addrsize != 4 && pd->name[0] != '$')))
{
da->warnings |= DAW_PREFIX;
da->cmdtype |= C_RARE;
}
// 16-bit addressing is rare in 32-bit programs. If this is the case,
// mark command as rare to help in analysis.
// 16位的寻址在32位程序中是少见的,如果是这种情况,在命令中加上标志
if (addrsize != 4)
da->cmdtype |= C_RARE;
}
// Suffix of 3DNow! command is accounted best by assuming it immediate byte
// constant.
// 如果是一个3dNow指令
if (is3dnow)
{
if (immsize != 0)
da->error = DAE_BADCMD;
else
immsize = 1;
}
// Right or wrong, command decoded. Now dump it.
if (da->error != 0) // 如果命令有错误
{
// Hard error in command detected
if (mode >= DISASM_FILE)
nresult = sprintf(da->result, "???");
if (da->error == DAE_BADCMD && (*cmd == 0x0F || *cmd == 0xFF) && size > 0)
{
if (mode >= DISASM_FILE)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd);
da->hexcode[da->codelen++] = *cmd;
}
cmd++;
size--;
}
if (size>0)
{
if (mode >= DISASM_FILE)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd);
da->hexcode[da->codelen++] = *cmd;
}
cmd++;
size--;
}
}
else
{
//如果没有错误,dump命令
// No hard error, dump command
if (mode >= DISASM_FILE)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd++);
da->hexcode[da->codelen++] = *(cmd - 1);
if (hasrm)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd++);
da->hexcode[da->codelen++] = *(cmd - 1);
}
if (hassib)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd++);
da->hexcode[da->codelen++] = *(cmd - 1);
}
if (dispsize != 0)
{
da->dump[ndump++] = ' ';
for (i = 0; i < dispsize; i++)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd++);
da->hexcode[da->codelen++] = *(cmd - 1);
}
}
if (immsize != 0)
{
da->dump[ndump++] = ' ';
for (i = 0; i < immsize; i++)
{
ndump += sprintf(da->dump + ndump, "%02X", *cmd++);
da->hexcode[da->codelen++] = *(cmd - 1);
}
}
}
else
cmd += 1 + hasrm + hassib + dispsize + immsize;
size -= 1 + hasrm + hassib + dispsize + immsize;
}
// Check that command is not a dangerous one.
// 检查命令是否是危险的
if (mode >= DISASM_DATA)
{
for (pdan = dangerous; pdan->mask != 0; pdan++)
{
if (((code ^ pdan->code) & pdan->mask) != 0)
continue;
if (pdan->type == C_DANGERLOCK && lockprefix == 0)
break; // Command harmless without LOCK prefix
if (iswindowsnt && pdan->type == C_DANGER95)
break; // Command harmless under Windows NT
// Dangerous command!
if (pdan->type == C_DANGER95)
da->warnings |= DAW_DANGER95;
else
da->warnings |= DAW_DANGEROUS;
break;
}
}
if (da->error == 0 && softerror != 0)
da->error = softerror; // Error, but still display command
if (mode >= DISASM_FILE)
{
// 根据错误处理
if (da->error != DAE_NOERR)
{
switch (da->error)
{
case DAE_CROSS:
strcpy(da->comment, "Command crosses end of memory block");
break;
case DAE_BADCMD:
strcpy(da->comment, "Unknown command");
break;
case DAE_BADSEG:
strcpy(da->comment, "Undefined segment register");
break;
case DAE_MEMORY:
strcpy(da->comment, "Illegal use of register");
break;
case DAE_REGISTER:
strcpy(da->comment, "Memory address not allowed");
break;
case DAE_INTERN:
strcpy(da->comment, "Internal OLLYDBG error");
break;
default:
strcpy(da->comment, "Unknown error");
break;
}
}
// 特权指令,发出警告
else if ((da->warnings & DAW_PRIV) != 0 && privileged == 0)
strcpy(da->comment, "Privileged command");
// IO指令
else if ((da->warnings & DAW_IO) != 0 && iocommand == 0)
strcpy(da->comment, "I/O command");
else if ((da->warnings & DAW_FARADDR) != 0 && farcalls == 0)
{
if ((da->cmdtype & C_TYPEMASK) == C_JMP)
strcpy(da->comment, "Far jump");
else if ((da->cmdtype & C_TYPEMASK) == C_CAL)
strcpy(da->comment, "Far call");
else if ((da->cmdtype & C_TYPEMASK) == C_RET)
strcpy(da->comment, "Far return");
}
else if ((da->warnings & DAW_SEGMENT) != 0 && farcalls == 0)
strcpy(da->comment, "Modification of segment register");
else if ((da->warnings & DAW_SHIFT) != 0 && badshift == 0)
strcpy(da->comment, "Shift constant out of range 1..31");
else if ((da->warnings & DAW_PREFIX) != 0 && extraprefix == 0)
strcpy(da->comment, "Superfluous prefix");
else if ((da->warnings & DAW_LOCK) != 0 && lockedbus == 0)
strcpy(da->comment, "LOCK prefix");
else if ((da->warnings & DAW_STACK) != 0 && stackalign == 0)
strcpy(da->comment, "Unaligned stack operation");
}
return (srcsize - size); // Returns number of recognized bytes
}
// --------------------------- disasm.h -------------
// Free Disassembler and Assembler -- Header file
//
// Copyright (C) 2001 Oleh Yuschuk
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#pragma once
#ifndef MAINPROG
#define odunique extern
#else
#define odunique
#endif
#pragma warning(disable:4309)//关闭截断常数值警告
// If you prefere Borland, this will force necessary setting (but, as a side
// effect, may cause plenty of warnings if other include files will be compiled
// with different options):
#ifdef __BORLANDC__
#pragma option -K // Unsigned char
#endif
//
//#if (char)0xFF != 255
//#error Please set default char type to unsigned
//#endif
#define NEGLIMIT (-16384) // Limit to display constans as signed
// 假操作数,伪操作数
#define PSEUDOOP 128 // Base for pseudooperands
#define TEXTLEN 256 // Maximal length of text string
// Special command features.
#define WW 0x01 // Bit W (size of operand)
#define SS 0x02 // Bit S (sign extention of immediate)
#define WS 0x03 // Bits W and S
#define W3 0x08 // Bit W at position 3
#define CC 0x10 // Conditional jump
// 强制要求16位长度的操作数
#define FF 0x20 // Forced 16-bit size
#define LL 0x40 // Conditional loop
// 特权指令
#define PR 0x80 // Protected command
// IO指令
#define WP 0x81 // I/O command with bit W
// All possible types of operands in 80x86. A bit more than you expected, he?
// 操作数类型
#define NNN 0 // No operand \\ 无操作
// 寄存器操作数
// 对于汇编指令,有些指令的操作数是寄存器,并且在指令中需指定操作数是哪个寄存器
// 而有些指令的操作数是寄存器,但不需要指定用哪个寄存器,而是指令
// 一旦确定下来,则使用的寄存器也就确定了 [??]
// 下面两个类型是否分别指上面的两种情况
#define REG 1 // Integer register in Reg field \\积存器结构中的寄存器
#define RCM 2 // Integer register in command byte \\命令字节中的寄存器
#define RG4 3 // Integer 4-byte register in Reg field \\用不到PMOVMSKB指令
#define RAC 4 // Accumulator (AL/AX/EAX, implicit) \\暗示累加器?
#define RAX 5 // AX (2-byte, implicit) \\暗示AX
#define RDX 6 // DX (16-bit implicit port address)
#define RCL 7 // Implicit CL register (for shifts) \\暗示CL寄存器
#define RS0 8 // Top of FPU stack (ST(0), implicit)
// FPU寄存器操作数
#define RST 9 // FPU register (ST(i)) in command byte
// MMX寄存器操作数
#define RMX 10 // MMX register MMx
#define R3D 11 // 3DNow! register MMx
#define MRG 12 // Memory/register in ModRM byte
#define MR1 13 // 1-byte memory/register in ModRM byte
#define MR2 14 // 2-byte memory/register in ModRM byte
#define MR4 15 // 4-byte memory/register in ModRM byte
#define RR4 16 // 4-byte memory/register (register only)
#define MR8 17 // 8-byte memory/MMX register in ModRM
#define RR8 18 // 8-byte MMX register only in ModRM
#define MRD 19 // 8-byte memory/3DNow! register in ModRM
#define RRD 20 // 8-byte memory/3DNow! (register only)
#define MRJ 21 // Memory/reg in ModRM as JUMP target
#define MMA 22 // Memory address in ModRM byte for LEA
#define MML 23 // Memory in ModRM byte (for LES)
#define MMS 24 // Memory in ModRM byte (as SEG:OFFS)
#define MM6 25 // Memory in ModRm (6-byte descriptor)
#define MMB 26 // Two adjacent memory locations (BOUND)
#define MD2 27 // Memory in ModRM (16-bit integer)
#define MB2 28 // Memory in ModRM (16-bit binary)
#define MD4 29 // Memory in ModRM byte (32-bit integer)
#define MD8 30 // Memory in ModRM byte (64-bit integer)
#define MDA 31 // Memory in ModRM byte (80-bit BCD)
#define MF4 32 // Memory in ModRM byte (32-bit float)
#define MF8 33 // Memory in ModRM byte (64-bit float)
#define MFA 34 // Memory in ModRM byte (80-bit float)
#define MFE 35 // Memory in ModRM byte (FPU environment)
#define MFS 36 // Memory in ModRM byte (FPU state)
#define MFX 37 // Memory in ModRM byte (ext. FPU state)
#define MSO 38 // Source in string op's ([ESI])
#define MDE 39 // Destination in string op's ([EDI])
// XLAT操作数
#define MXL 40 // XLAT operand ([EBX+AL])
// 直接数
#define IMM 41 // Immediate data (8 or 16/32)
#define IMU 42 // Immediate unsigned data (8 or 16/32)
#define VXD 43 // VxD service
#define IMX 44 // Immediate sign-extendable byte
#define C01 45 // Implicit constant 1 (for shifts)
#define IMS 46 // Immediate byte (for shifts)
#define IM1 47 // Immediate byte
#define IM2 48 // Immediate word (ENTER/RET)
#define IMA 49 // Immediate absolute near data address
#define JOB 50 // Immediate byte offset (for jumps)
#define JOW 51 // Immediate full offset (for jumps)
// 操作数是JMP跳转或call的地址
#define JMF 52 // Immediate absolute far jump/call addr
// 段寄存器操作
#define SGM 53 // Segment register in ModRM byte
#define SCM 54 // 段寄存器 Segment register in command byte
// 控制寄存器操作数
#define CRX 55 // CRx控制寄存器 Control register CRx
// 调试寄存器操作数
#define DRX 56 // DRx调试寄存器 Debug register DRx
// Pseudooperands (implicit operands, never appear in assembler commands). Must
// have index equal to or exceeding PSEUDOOP.
#define PRN (PSEUDOOP+0) // Near return address
#define PRF (PSEUDOOP+1) // Far return address
#define PAC (PSEUDOOP+2) // Accumulator (AL/AX/EAX)
#define PAH (PSEUDOOP+3) // AH (in LAHF/SAHF commands)
#define PFL (PSEUDOOP+4) // Lower byte of flags (in LAHF/SAHF)
#define PS0 (PSEUDOOP+5) // Top of FPU stack (ST(0))
#define PS1 (PSEUDOOP+6) // ST(1)
#define PCX (PSEUDOOP+7) // CX/ECX
#define PDI (PSEUDOOP+8) // EDI (in MMX extentions)
// Errors detected during command disassembling.
#define DAE_NOERR 0 // No error
// 错误的指令
#define DAE_BADCMD 1 // Unrecognized command
#define DAE_CROSS 2 // Command crosses end of memory block
#define DAE_BADSEG 3 // Undefined segment register
// 当操作数必须是内存操作数,而发现操作数是寄存器时出的错误
#define DAE_MEMORY 4 // Register where only memory allowed
#define DAE_REGISTER 5 // Memory where only register allowed
// 内部错误
#define DAE_INTERN 6 // Internal error
typedef unsigned char uchar; // Unsigned character (byte)
typedef unsigned short ushort; // Unsigned short
typedef unsigned int uint; // Unsigned integer
typedef unsigned long ulong; // Unsigned long
typedef struct t_addrdec
{
int defseg;
char *descr;
} t_addrdec;
// 命令数据
typedef struct t_cmddata
{
ulong mask; // Mask for first 4 bytes of the command
ulong code; // Compare masked bytes with this
char len; // Length of the main command code
// 例如PR,则表明该指令是一特权指令(ring 0指令)
// FF:强制操作数为16位操作数
char bits; // Special bits within the command
char arg1,arg2,arg3; // Types of possible arguments
char type; // C_xxx + additional information
char *name; // Symbolic name for this command
} t_cmddata;
// Initialized constant data structures used by all programs from assembler
// package. Contain names of register, register combinations or commands and
// their properties.
extern const char *regname[3][9];
extern const char *segname[8];
extern const char *sizename[11];
extern const t_addrdec addr16[8];
extern const t_addrdec addr32[8];
extern const char *fpuname[9];
extern const char *mmxname[9];
extern const char *crname[9];
extern const char *drname[9];
extern const char *condition[16];
extern const t_cmddata cmddata[];//可用结构数组
extern const t_cmddata vxdcmd;
extern const t_cmddata dangerous[];
////////////////////////////////////////////////////////////////////////////////
//////////////////// ASSEMBLER, DISASSEMBLER AND EXPRESSIONS ///////////////////
#define MAXCMDSIZE 16 // Maximal length of 80x86 command
#define MAXCALSIZE 8 // Max length of CALL without prefixes
#define NMODELS 8 // Number of assembler search models
#define INT3 0xCC // Code of 1-byte breakpoint
#define NOP 0x90 // Code of 1-byte NOP command
#define TRAPFLAG 0x00000100 // Trap flag in CPU flag register
#define REG_EAX 0 // Indexes of general-purpose registers
#define REG_ECX 1 // in t_reg.
#define REG_EDX 2
#define REG_EBX 3
#define REG_ESP 4
#define REG_EBP 5
#define REG_ESI 6
#define REG_EDI 7
#define SEG_UNDEF -1 //没有段寄存器
#define SEG_ES 0 // Indexes of segment/selector registers
#define SEG_CS 1
#define SEG_SS 2
#define SEG_DS 3
#define SEG_FS 4
#define SEG_GS 5
// 指令类型
#define C_TYPEMASK 0xF0 // Mask for command type
#define C_CMD 0x00 // Ordinary instruction
#define C_PSH 0x10 // 1-word PUSH instruction
#define C_POP 0x20 // 1-word POP instruction
#define C_MMX 0x30 // MMX instruction
#define C_FLT 0x40 // FPU instruction
// jmp跳转指令
#define C_JMP 0x50 // JUMP instruction
// jmp条件跳转指令
#define C_JMC 0x60 // Conditional JUMP instruction
// call调用指令
#define C_CAL 0x70 // CALL instruction
#define C_RET 0x80 // RET instruction
#define C_*** 0x90 // Changes system flags
#define C_RTF 0xA0 // C_JMP and C_*** simultaneously
#define C_REP 0xB0 // Instruction with REPxx prefix
#define C_PRI 0xC0 // Privileged instruction
#define C_DAT 0xD0 // Data (address) doubleword
// 3DNow 指令
#define C_NOW 0xE0 // 3DNow! instruction
// 错误指令,即未注册的指令
#define C_BAD 0xF0 // Unrecognized command
#define C_RARE 0x08 // Rare command, seldom used in programs
#define C_SIZEMASK 0x07 // MMX data size or special flag
#define C_EXPL 0x01 // (non-MMX) Specify explicit memory size
#define C_DANGER95 0x01 // Command is dangerous under Win95/98
#define C_DANGER 0x03 // Command is dangerous everywhere
#define C_DANGERLOCK 0x07 // Dangerous with LOCK prefix
#define DEC_TYPEMASK 0x1F // Type of memory byte
#define DEC_UNKNOWN 0x00 // Unknown type
#define DEC_BYTE 0x01 // Accessed as byte
#define DEC_WORD 0x02 // Accessed as short
#define DEC_NEXTDATA 0x03 // Subsequent byte of code or data
#define DEC_DWORD 0x04 // Accessed as long
#define DEC_FLOAT4 0x05 // Accessed as float
#define DEC_FWORD 0x06 // Accessed as descriptor/long pointer
#define DEC_FLOAT8 0x07 // Accessed as double
#define DEC_QWORD 0x08 // Accessed as 8-byte integer
#define DEC_FLOAT10 0x09 // Accessed as long double
#define DEC_TBYTE 0x0A // Accessed as 10-byte integer
#define DEC_STRING 0x0B // Zero-terminated ASCII string
#define DEC_UNICODE 0x0C // Zero-terminated UNICODE string
// 3DNow指令操作数
#define DEC_3DNOW 0x0D // Accessed as 3Dnow operand
#define DEC_BYTESW 0x11 // Accessed as byte index to switch
#define DEC_NEXTCODE 0x13 // Subsequent byte of command
#define DEC_COMMAND 0x1D // First byte of command
#define DEC_JMPDEST 0x1E // Jump destination
#define DEC_CALLDEST 0x1F // Call (and maybe jump) destination
#define DEC_PROCMASK 0x60 // Procedure analysis
#define DEC_PROC 0x20 // Start of procedure
#define DEC_PBODY 0x40 // Body of procedure
#define DEC_PEND 0x60 // End of procedure
#define DEC_CHECKED 0x80 // Byte was analysed
#define DECR_TYPEMASK 0x3F // Type of register or memory
#define DECR_BYTE 0x21 // Byte register
#define DECR_WORD 0x22 // Short integer register
#define DECR_DWORD 0x24 // Long integer register
#define DECR_QWORD 0x28 // MMX register
#define DECR_FLOAT10 0x29 // Floating-point register
#define DECR_SEG 0x2A // Segment register
#define DECR_3DNOW 0x2D // 3Dnow! register
#define DECR_ISREG 0x20 // Mask to check that operand is register
/**
* 反汇编的选项
*/
#define DISASM_SIZE 0 // Determine command size only
#define DISASM_DATA 1 // Determine size and analysis data
#define DISASM_FILE 3 // Disassembly, no symbols
#define DISASM_CODE 4 // Full disassembly
// Warnings issued by Disasm():
#define DAW_FARADDR 0x0001 // Command is a far jump, call or return
// 当执行如MOV SEG, XX的指令时警告
#define DAW_SEGMENT 0x0002 // Command loads segment register
// 特权指令
#define DAW_PRIV 0x0004 // Privileged command
// IO指令
#define DAW_IO 0x0008 // I/O command
#define DAW_SHIFT 0x0010 // Shift constant out of range 1..31
// 表示指令有过多的前缀
#define DAW_PREFIX 0x0020 // Superfluous prefix
// 指令有加锁总线前缀
#define DAW_LOCK 0x0040 // Command has LOCK prefix
// 栈没有对齐(一般栈操作需要双字对齐)
#define DAW_STACK 0x0080 // Unaligned stack operation
#define DAW_DANGER95 0x1000 // May mess up Win95 if executed
#define DAW_DANGEROUS 0x3000 // May mess up any OS if executed
//bughoho 操作数类型
enum Optype
{
// 立即数
Imm,
// 寄存器
Reg,
// 内存数
Mem,
// 段寄存器
Seg,
};
// Results of disassembling
/**
* 用于保存反汇编的结果
*/
typedef struct t_disasm
{
// 应该是指令本身所在的地址
ulong ip; // Instrucion pointer
char dump[TEXTLEN]; // Hexadecimal dump of the command
// 用于保存反汇编指令
char result[TEXTLEN]; // Disassembled command
// 对指令的一些说明信息,比如可包含信息"Superfluous prefix"以表示指令的前缀过多
char comment[TEXTLEN]; // Brief comment
// 表示指令的类型
// C_RARE: 表示指令比较罕见,在程序中不常用
// C_CAL:表示是一个CALL指令
//
int cmdtype; // One of C_xxx
// DEC_BYTE:表示是一个字节内存操作数
// DEC_3DNOW:表示是一个3dNow指令操作数
int memtype; // Type of addressed variable in memory
// 统计指令的前缀数
int nprefix; // Number of prefixes
// 地址是否存在寄存器(index)
int indexed; // Address contains register(s)
// 常量跳转地址 [??]
ulong jmpconst; // Constant jump address
// 跳转表,可能赋值为:jmptable = addr;
ulong jmptable; // Possible address of switch table
ulong adrconst; // [edx+100] '100' 地址部分的常量 Constant part of address
// 保存操作数(立即数)的值
ulong immconst; // Immediate constant
// 1:表示adrconst为0
int zeroconst; // Whether contains zero constant
int fixupoffset; // Possible offset of 32-bit fixups
int fixupsize; // Possible total size of fixups or 0
int error; // Error while disassembling command
// 反汇编过程中需要进行警告的信息
// 如DAW_PRIV,则表明指令是一个特权指令(ring 0)指令
int warnings; // Combination of DAW_xxx
//bughoho new
BYTE hexcode[TEXTLEN]; // 用于存储2进制码
int codelen; // 长度
int optype[3]; // 操作数类型
char vm_name[TEXTLEN]; // 声称VM对应的Handler名称
// 3dNow指令
int is3dnow; // 3dnow函数
int segment; // 保存段前缀
// 当操作数为寄存器时,存储寄存器编号
int reg[3]; // 3寄存器(假设操作数为寄存器)
int segreg; // 段寄存器(假设操作数为段寄存器)
int addrreg1; // 内存地址部分的第1个不带比例的寄存器
int addrreg2; // 内存地址部分的第2个带比例的寄存器
int regsscale; // 比例:1,2,4,8
//还有一个adrconst已经定义,根据正负号来定义加减
int memsize[3]; // 操作数长度
// 当某个操作数是(ah,bh,ch,dh)时,即寄存器的高8位时,则相应元素置true
bool highbit[3]; // 当是8位指令时并且为高位时(ah bh ch dh)为1
} t_disasm;
/**
* 用于保存反汇编的每个指令语句
*/
struct CodeNode
{
t_disasm disasm;
// 表示此指令是跳到外部的指令
BOOL IsJmcBeSideType;
// 指令跳转地址不明确
BOOL IsJmcUndefineType;
// 此指令是一动态跳转指令
// 注:动态跳转指令指没有指明跳转地址的跳转指令
BOOL IsJmcDynamicType;
// TRUE表示指令是一跳转指令
BOOL IsJmcType;
// 表示此指令是否是从其他指令处跳转过来
BOOL IsJmcFromType;
// 表示此指令是JMC或CALL指令后的指令
BOOL IsJmcNextType;
// 表示该指令是一CALL指令
BOOL IsCallType;
CodeNode()
{
memset(this,0,sizeof(CodeNode));
}
};
/**
* 虚拟机指令相应的汇编代码必须编译成二进制机器代码,此结构就用于
* 表示某段编译之后的二进制机器代码及代码的一些相关信息
*/
typedef struct t_asmmodel
{ // Model to search for assembler command
// 存储解码后的机器指令
char code[MAXCMDSIZE]; // Binary code
char mask[MAXCMDSIZE]; // Mask for binary code (0: bit ignored)
// 指令长度
int length; // Length of code, bytes (0: empty)
int jmpsize; // Offset size if relative jump
int jmpoffset; // Offset relative to IP
int jmppos; // Position of jump offset in command
} t_asmmodel;
odunique int ideal; // Force IDEAL decoding mode
odunique int lowercase; // Force lowercase display
odunique int tabarguments; // Tab between mnemonic and arguments
odunique int extraspace; // Extra space between arguments
odunique int putdefseg; // Display default segments in listing
odunique int showmemsize; // Always show memory size
odunique int shownear; // Show NEAR modifiers
odunique int shortstringcmds; // Use short form of string commands
odunique int sizesens; // How to decode size-sensitive mnemonics
odunique int symbolic; // Show symbolic addresses in disasm
odunique int farcalls; // Accept far calls, returns & addresses
odunique int decodevxd; // Decode VxD calls (Win95/98)
odunique int privileged; // Accept privileged commands
odunique int iocommand; // Accept I/O commands
odunique int badshift; // Accept shift out of range 1..31
odunique int extraprefix; // Accept superfluous prefixes
odunique int lockedbus; // Accept LOCK prefixes
odunique int stackalign; // Accept unaligned stack operations
odunique int iswindowsnt; // When checking for dangers, assume NT
//bughoho
odunique int stoperand; //当前的循环
int Assemble(char *cmd,ulong ip,t_asmmodel *model,int attempt,
int constsize,char *errtext);
int Checkcondition(int code,ulong flags);
int Decodeaddress(ulong addr,char *symb,int nsymb,char *comment);
ulong Disasm(char *src,ulong srcsize,ulong srcip,
t_disasm *disasm,int disasmmode);
ulong Disassembleback(char *block,ulong base,ulong size,ulong ip,int n);
ulong Disassembleforward(char *block,ulong base,ulong size,ulong ip,int n);
int Isfilling(ulong addr,char *data,ulong size,ulong align);
int Print3dnow(char *s,char *f);
int Printfloat10(char *s,long double ext);
int Printfloat4(char *s,float f);
int Printfloat8(char *s,double d);
