欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

编译部分

编译部分

// ----------------------------------------- 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);

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功