首页
社区
课程
招聘
[原创] Valgrind VEX IR
发表于: 2020-3-31 00:04 9256

[原创] Valgrind VEX IR

2020-3-31 00:04
9256

最近在学习angr,里面有用到vex ir,之前对vex ir不了解,打算系统学习一遍。


1.code blocks:

         代码被分割成很多小的代码片段(类型为'IRSB'),每个块表示1~50条指令。IRSB块是单入口,多出口。每个IRSB包含以下三种数据:


2.statements and expression

    Statements(‘IRStmt'):代表有着副作用的操作,eg. 寄存器写,存储和分配给临时变量。

    Expressiongs('IRExpr') :代表着没有副作用的操作,eg,算术运算,加载,常量


3.storage of guest state

        “guest state”包含guest machine(即我们正在模拟的机器)的guest寄存器。默认情况下,它存储在VEX库用户提供的内存块中,通常称guest state(area)。要对这些寄存器进行操作,必须首先将它们从guest state读取(“Get”)为一个临时值。之后,可以将它们写回("put") guest state。

         Get和Put的特征是进入guest状态的字节偏移量、一个有效给出被引用guest寄存器标识的小整数和一个指示要传输的值大小的类型。

         基本的“Get”和“Put”操作足以对guest 上的正常固定寄存器建模。guest stated 的选定区域可以视为寄存器的循环数组(类型:“IRRegArray”),可以在运行时对其进行索引。这是用“GetI”和“PutI”原语完成的。这是描述旋转寄存器文件所必需的,例如x87 FPU堆栈、SPARC寄存器窗口和Itanium寄存器文件。

4.例子:考虑如下x86指令

可能的IR代码如下

IMark只是IR声明,不代表实际的指令,指明了代码的地址0x24f275,原始指令的长度7,数字0和12偏移到%eax和%ebx的guest state。(这里的0代表%eax吧)

本例中的五个 statements 是:

VEX ir 类型定义

       一个常量,存储为带标记的联合体,tag 表示这是一个什么样的常数Ico是一个union,它控制着各个领域。如果 IRConst'c' 的c.tag等于Ico_U32,则它是32位常量,其值可以使用'c.Ico.U32'访问

7.call targets

       描述要调用的帮助函数。名字部分纯粹是为了漂亮的打印而不是实际使用。regparms=n告诉后端被调用方已被声明为“__attribute__(regparm(n))”,尽管间接使用VEX_REGPARM(n)宏。在某些目标(x86)上,后端需要构造一个非标准序列来调用这样声明的函数。

       mcx_mask 是一种记忆检查的标准。它指出在计算结果的定义时,哪些参数应该被视为“总是定义的”。mcx_mask的位0对应于args[0],位1对应于args[1]等。如果设置了位,则从定义性检查中排除相应的arg(因此“mcx”中的“x”)。

       它们的含义在下面的IRExpr注释中解释。存储为标记的联合。 “标签”指示这是一种表达。 “ Iex”是持有字段的联合。 如果IRExpr'e'具有等于Iex_Load的e.tag,则它是一个负载表达式,并且可以使用'e.Iex.Load。<fieldname>'访问这些字段。

Memory Bus Events

Compare and Swap

basic block

        类型环境:一堆语句、表达式等都是不完整的,没有一个环境指示每个IRTemp的类型。所以这就提供了一个。IR临时变量实际上只是无符号整数,因此它提供一个数组0。。n_类型使用-1个。

本片文章主要参考angr官方文档:
简介:


1.code blocks:

         代码被分割成很多小的代码片段(类型为'IRSB'),每个块表示1~50条指令。IRSB块是单入口,多出口。每个IRSB包含以下三种数据:

  •          -a type enviroment, 它指示IRSB中存在的每个临时值的类型。
  •          -a list of statement, 表示对应的代码
  •          -a jump that exits from the end the IRSB:退出IRSB


2.statements and expression

    Statements(‘IRStmt'):代表有着副作用的操作,eg. 寄存器写,存储和分配给临时变量。

    Expressiongs('IRExpr') :代表着没有副作用的操作,eg,算术运算,加载,常量


3.storage of guest state

        “guest state”包含guest machine(即我们正在模拟的机器)的guest寄存器。默认情况下,它存储在VEX库用户提供的内存块中,通常称guest state(area)。要对这些寄存器进行操作,必须首先将它们从guest state读取(“Get”)为一个临时值。之后,可以将它们写回("put") guest state。

         Get和Put的特征是进入guest状态的字节偏移量、一个有效给出被引用guest寄存器标识的小整数和一个指示要传输的值大小的类型。

         基本的“Get”和“Put”操作足以对guest 上的正常固定寄存器建模。guest stated 的选定区域可以视为寄存器的循环数组(类型:“IRRegArray”),可以在运行时对其进行索引。这是用“GetI”和“PutI”原语完成的。这是描述旋转寄存器文件所必需的,例如x87 FPU堆栈、SPARC寄存器窗口和Itanium寄存器文件。


4.例子:考虑如下x86指令

		addl %eax,%ebx

可能的IR代码如下

		------ IMark(0x24F275, 7, 0) ------
		     t3 = GET:I32(0)             # get %eax, a 32-bit integer
		     t2 = GET:I32(12)            # get %ebx, a 32-bit integer
		     t1 = Add32(t3,t2)           # addl
		     PUT(0) = t1                 # put %eax

IMark只是IR声明,不代表实际的指令,指明了代码的地址0x24f275,原始指令的长度7,数字0和12偏移到%eax和%ebx的guest state。(这里的0代表%eax吧)

本例中的五个 statements 是:

  •    the Imark
  •   三条对临时变量的赋值

                        addl %edx,4(%eax)
		 ------ IMark(0x4000ABA, 3, 0) ------
		     t3 = Add32(GET:I32(0),0x4:I32)   //0表示%eax寄存器
		     t2 = LDle:I32(t3)
		     t1 = GET:I32(8)             //8表示%edx寄存器
		     t0 = Add32(t2,t1)
		     STle(t3) = t0
		“LDle"和"STle"中的'le'是'little-endian'的缩写





		addl %eax,%ebx
		------ IMark(0x24F275, 7, 0) ------
		     t3 = GET:I32(0)             # get %eax, a 32-bit integer
		     t2 = GET:I32(12)            # get %ebx, a 32-bit integer
		     t1 = Add32(t3,t2)           # addl
		     PUT(0) = t1                 # put %eax

IMark只是IR声明,不代表实际的指令,指明了代码的地址0x24f275,原始指令的长度7,数字0和12偏移到%eax和%ebx的guest state。(这里的0代表%eax吧)

本例中的五个 statements 是:

  •    the Imark
  •   三条对临时变量的赋值

                        addl %edx,4(%eax)
		 ------ IMark(0x4000ABA, 3, 0) ------
		     t3 = Add32(GET:I32(0),0x4:I32)   //0表示%eax寄存器
		     t2 = LDle:I32(t3)
		     t1 = GET:I32(8)             //8表示%edx寄存器
		     t0 = Add32(t2,t1)
		     STle(t3) = t0
		“LDle"和"STle"中的'le'是'little-endian'的缩写


                        addl %edx,4(%eax)
		 ------ IMark(0x4000ABA, 3, 0) ------
		     t3 = Add32(GET:I32(0),0x4:I32)   //0表示%eax寄存器
		     t2 = LDle:I32(t3)
		     t1 = GET:I32(8)             //8表示%edx寄存器
		     t0 = Add32(t2,t1)
		     STle(t3) = t0
		“LDle"和"STle"中的'le'是'little-endian'的缩写




7.

VEX ir 类型定义

typedef 
   enum { 
      Ity_INVALID=0x1100,
      Ity_I1, 
      Ity_I8, 
      Ity_I16, 
      Ity_I32, 
      Ity_I64,
      Ity_I128,  /* 128-bit scalar */
      Ity_F16,   /* 16 bit float */
      Ity_F32,   /* IEEE 754 float */
      Ity_F64,   /* IEEE 754 double */
      Ity_D32,   /* 32-bit Decimal floating point */
      Ity_D64,   /* 64-bit Decimal floating point */
      Ity_D128,  /* 128-bit Decimal floating point */
      Ity_F128,  /* 128-bit floating point; implementation defined */
      Ity_V128,  /* 128-bit SIMD */
      Ity_V256   /* 256-bit SIMD */
   }
   IRType;
/* 打印 IRType */
extern void ppIRType ( IRType );

/*获取 IRType 字节大小 */ 
extern Int sizeofIRType ( IRType );

/* 将 1/2/4/8 转换成Ity_I{8,16,32,64}   */
extern IRType integerIRTypeOfSize ( Int szB );

IREndness用于加载IRExprs和存储IRStmts。
	typedef
	   enum { 
	      Iend_LE=0x1200, /* little endian */
	      Iend_BE          /* big endian */
	   }
   IREndness;

typedef 
   enum { 
      Ity_INVALID=0x1100,
      Ity_I1, 
      Ity_I8, 
      Ity_I16, 
      Ity_I32, 
      Ity_I64,
      Ity_I128,  /* 128-bit scalar */
      Ity_F16,   /* 16 bit float */
      Ity_F32,   /* IEEE 754 float */
      Ity_F64,   /* IEEE 754 double */
      Ity_D32,   /* 32-bit Decimal floating point */
      Ity_D64,   /* 64-bit Decimal floating point */
      Ity_D128,  /* 128-bit Decimal floating point */
      Ity_F128,  /* 128-bit floating point; implementation defined */
      Ity_V128,  /* 128-bit SIMD */
      Ity_V256   /* 256-bit SIMD */
   }
   IRType;
/* 打印 IRType */
extern void ppIRType ( IRType );

/*获取 IRType 字节大小 */ 
extern Int sizeofIRType ( IRType );

/* 将 1/2/4/8 转换成Ity_I{8,16,32,64}   */
extern IRType integerIRTypeOfSize ( Int szB );

IREndness用于加载IRExprs和存储IRStmts。
	typedef
	   enum { 
	      Iend_LE=0x1200, /* little endian */
	      Iend_BE          /* big endian */
	   }
   IREndness;

常量
	IRConsts在“ Const”和“ Exit” IRExprs中使用。
	typedef
	   enum { 
	      Ico_U1=0x1300,
	      Ico_U8, 
	      Ico_U16, 
	      Ico_U32, 
	      Ico_U64,
	      Ico_F32,   /* 32-bit IEEE754 floating */
	      Ico_F32i,  /* 32-bit unsigned int to be interpreted literally
	                    as a IEEE754 single value. */
	      Ico_F64,   /* 64-bit IEEE754 floating */
	      Ico_F64i,  /* 64-bit unsigned int to be interpreted literally
	                    as a IEEE754 double value. */
	      Ico_V128,  /* 128-bit restricted vector constant, with 1 bit
	                    (repeated 8 times) for each of the 16 x 1-byte lanes */
	      Ico_V256   /* 256-bit restricted vector constant, with 1 bit
	                    (repeated 8 times) for each of the 32 x 1-byte lanes */
	   }
	   IRConstTag;

       一个常量,存储为带标记的联合体,tag 表示这是一个什么样的常数Ico是一个union,它控制着各个领域。如果 IRConst'c' 的c.tag等于Ico_U32,则它是32位常量,其值可以使用'c.Ico.U32'访问

7.call targets

       描述要调用的帮助函数。名字部分纯粹是为了漂亮的打印而不是实际使用。regparms=n告诉后端被调用方已被声明为“__attribute__(regparm(n))”,尽管间接使用VEX_REGPARM(n)宏。在某些目标(x86)上,后端需要构造一个非标准序列来调用这样声明的函数。

       mcx_mask 是一种记忆检查的标准。它指出在计算结果的定义时,哪些参数应该被视为“总是定义的”。mcx_mask的位0对应于args[0],位1对应于args[1]等。如果设置了位,则从定义性检查中排除相应的arg(因此“mcx”中的“x”)。

	typedef
	   struct {
	      Int          regparms;
	      const HChar* name;
	      void*        addr;
	      UInt         mcx_mask;
	   }
	   IRCallee;
	
	/* Create an IRCallee. */
	extern IRCallee* mkIRCallee ( Int regparms, const HChar* name, void* addr );
	
	/* Deep-copy an IRCallee. */
	extern IRCallee* deepCopyIRCallee ( const IRCallee* );
	
	/* Pretty-print an IRCallee. */
	extern void ppIRCallee ( const IRCallee* );

	typedef struct _IRQop   IRQop;   /* forward declaration */
	typedef struct _IRTriop IRTriop; /* forward declaration */
	对于每种类型的表达式,可以使用ppIrExpr()来显示
	不同种类的表达式:
	typedef
	   enum { 
	      Iex_Binder=0x1900,
	      Iex_Get,
	      Iex_GetI,
	      Iex_RdTmp,
	      Iex_Qop,
	      Iex_Triop,
	      Iex_Binop,
	      Iex_Unop,
	      Iex_Load,
	      Iex_Const,
	      Iex_ITE,
	      Iex_CCall,
	      Iex_VECRET,
	      Iex_BBPTR
	   }
	   IRExprTag;

       它们的含义在下面的IRExpr注释中解释。存储为标记的联合。 “标签”指示这是一种表达。 “ Iex”是持有字段的联合。 如果IRExpr'e'具有等于Iex_Load的e.tag,则它是一个负载表达式,并且可以使用'e.Iex.Load。<fieldname>'访问这些字段。

	struct _IRExpr {
	   IRExprTag tag;
	   union {
	      /* 仅用于Vex内的模式匹配。不应出现在vex之外 */
	      struct {
	         Int binder;
	      } Binder;
	
	/*在guest state的固定偏移量处读取来宾寄存器。ppIRExpr输出:GET:<ty>(<offset>),例如GET:I32(0)*/
	struct {
	         Int    offset;    /*guest state的偏移 */
	         IRType ty;        /* 要读取值的类型 */
	      } Get;
	
	/*
	        在guest state下以非固定偏移量读取来guest存器。这允许循环索引到guest state的一部分,这对于建模guest存器的身份直到运行时才知道的情况至关重要。一个例子是x87 FP寄存器堆栈。
	         要作为循环数组处理的guest state的一部分在IRRegArray'descr'字段中描述。它保存数组中第一个元素的偏移量、每个元素的类型和元素的数量。
	数组索引是相当间接地表示的,以一种使优化变得容易的方式:作为可变部分(“ix”字段)和恒定偏移量(“bias”字段)的总和。
	         由于索引是循环的,实际使用的数组索引计算为(ix+bias)%数组中的元素数。
	举个列子如下:
		(96:8xF64)[t39,-7]
	       描述一个由8个F64类型值组成的数组,第一个值的guest state偏移量为96。此数组的索引位置是(t39-7)%8。
	         正确地获得数组大小/类型是很重要的,因为IR优化会密切关注这些信息,以便在单独的GetI和PutI事件之间建立混叠/非混叠,后者用于确定何时可以重新排序等。输入不正确的信息将导致模糊的IR优化错误。*/
		ppIRExpr output: GETI<descr>[<ix>,<bias]
		                         eg. GETI(128:8xI8)[t1,0]
		 struct {
		         IRRegArray* descr; /*  被视为循环的guest state的一部分*/
		         IRExpr*     ix;    /* 索引到数组的可变部分 */
		         Int         bias;  /* 索引到数组的固定部分*/
		      } GetI;
	
	/*临时变量的存储
		ppIRExpr output: t<tmp>, eg. t1*/
	struct{
		ITRemp tmp;   /*临时变量号*/
		}RdTmp;
	
	/*四元运算。*/
	ppIRExpr output: <op>(<arg1>, <arg2>, <arg3>, <arg4>),
	                      eg. MAddF64r32(t1, t2, t3, t4)
	 struct {
	        IRQop* details;
	      } Qop;
	
	/*三元运算。
	ppIRExpr output: <op>(<arg1>, <arg2>, <arg3>),
	                      eg. MulF64(1, 2.0, 3.0)
	*/
	 struct {
	        IRTriop* details;
	      } Triop;
	
	/*二元运算。
	ppIRExpr output: <op>(<arg1>, <arg2>), eg. Add32(t1,t2)
	*/
	 struct {
	         IROp op;          /* op-code   */
	         IRExpr* arg1;     /* operand 1 */
	         IRExpr* arg2;     /* operand 2 */
	      } Binop;
	
	
	/*一元运算:ppIRExpr output: <op>(<arg>), eg. Neg8(t1)*/
	struct {
	         IROp    op;       /* op-code */
	         IRExpr* arg;      /* operand */
	      } Unop;
	
	/*加载内存数据——一个普通的加载,而不是一个链接的加载。加载链接(和存储条件)由IRStmt.LLSC表示,因为加载链接有副作用,因此在语义上不是有效的IRExpr。
	ppIRExpr output: LD<end>:<ty>(<addr>), eg. LDle:I32(t1)*/
	 struct {
	         IREndness end;    /* Endian-ness of the load */
	         IRType    ty;     /* Type of the loaded value */
	         IRExpr*   addr;   /* Address being loaded from */
	      } Load;
	
	/*常量表达式
	ppIRExpr output: <con>, eg. 0x4:I32*/
	struct {
	         IRConst* con;     /* The constant itself */
	      } Const;
	
	/*函数调用
	‘cee'中的'name’是函数名字,主要是为了更好的打印效果,'cee'中的'addr'保存函数地址。
	‘args' 是以NULL作为终结符的数字。IRType,表示参数类型。必须和函数调用相匹配。
	函数调用必须满足以下几个条件
		-没有副作用,函数结果只取决于传递过去的参数
		-它可能不会查看或修改任何guest state,因为这样会隐藏插入器的guest state转换
		-它可能无法访问guest内存,因为这会隐藏来自检测程序的guest内存事务
		-它不能假定参数是按特定顺序计算的。未指定求值顺序。
	原则上,允许arg向量包含一个IRExpr_VECRET(),尽管不是IRExpr_BBPTR()。但是,目前没有要求clean helper调用能够返回V128或V256值。因此这是不允许的。
	ppIRExpr output: <cee>(<args>):<retty>
	                      eg. foo{0x80489304}(t1, t2):I32*/
	 struct {
	         IRCallee* cee;    /* 调用的函数. */
	         IRType    retty;  /* 返回类型. */
	         IRExpr**  args;   /* 表达式向量. */
	      }  CCall;
	
	/*三元if-then-else运算符。如果cond不为零,则返回iftrue,否则返回iffalse。请注意,它是严格的,即在所有情况下都会对iftrue和iffalse进行评估。
	ppIRExpr output: ITE(<cond>,<iftrue>,<iffalse>),
	                         eg. ITE(t6,t7,t8)
	*/
	struct {
	         IRExpr* cond;     /* Condition */
	         IRExpr* iftrue;   /* True expression */
	         IRExpr* iffalse;  /* False expression */
	      } ITE;
	   } Iex;
};



	IRConsts在“ Const”和“ Exit” IRExprs中使用。
	typedef
	   enum { 
	      Ico_U1=0x1300,
	      Ico_U8, 
	      Ico_U16, 
	      Ico_U32, 
	      Ico_U64,
	      Ico_F32,   /* 32-bit IEEE754 floating */
	      Ico_F32i,  /* 32-bit unsigned int to be interpreted literally
	                    as a IEEE754 single value. */
	      Ico_F64,   /* 64-bit IEEE754 floating */
	      Ico_F64i,  /* 64-bit unsigned int to be interpreted literally
	                    as a IEEE754 double value. */
	      Ico_V128,  /* 128-bit restricted vector constant, with 1 bit
	                    (repeated 8 times) for each of the 16 x 1-byte lanes */
	      Ico_V256   /* 256-bit restricted vector constant, with 1 bit
	                    (repeated 8 times) for each of the 32 x 1-byte lanes */
	   }
	   IRConstTag;

       一个常量,存储为带标记的联合体,tag 表示这是一个什么样的常数Ico是一个union,它控制着各个领域。如果 IRConst'c' 的c.tag等于Ico_U32,则它是32位常量,其值可以使用'c.Ico.U32'访问

7.call targets

       描述要调用的帮助函数。名字部分纯粹是为了漂亮的打印而不是实际使用。regparms=n告诉后端被调用方已被声明为“__attribute__(regparm(n))”,尽管间接使用VEX_REGPARM(n)宏。在某些目标(x86)上,后端需要构造一个非标准序列来调用这样声明的函数。

       mcx_mask 是一种记忆检查的标准。它指出在计算结果的定义时,哪些参数应该被视为“总是定义的”。mcx_mask的位0对应于args[0],位1对应于args[1]等。如果设置了位,则从定义性检查中排除相应的arg(因此“mcx”中的“x”)。

	typedef
	   struct {
	      Int          regparms;
	      const HChar* name;
	      void*        addr;
	      UInt         mcx_mask;
	   }
	   IRCallee;
	
	/* Create an IRCallee. */
	extern IRCallee* mkIRCallee ( Int regparms, const HChar* name, void* addr );
	
	/* Deep-copy an IRCallee. */
	extern IRCallee* deepCopyIRCallee ( const IRCallee* );
	
	/* Pretty-print an IRCallee. */
	extern void ppIRCallee ( const IRCallee* );

	typedef struct _IRQop   IRQop;   /* forward declaration */
	typedef struct _IRTriop IRTriop; /* forward declaration */
	对于每种类型的表达式,可以使用ppIrExpr()来显示
	不同种类的表达式:
	typedef
	   enum { 
	      Iex_Binder=0x1900,
	      Iex_Get,
	      Iex_GetI,
	      Iex_RdTmp,
	      Iex_Qop,
	      Iex_Triop,
	      Iex_Binop,
	      Iex_Unop,
	      Iex_Load,
	      Iex_Const,
	      Iex_ITE,
	      Iex_CCall,
	      Iex_VECRET,
	      Iex_BBPTR
	   }
	   IRExprTag;

       它们的含义在下面的IRExpr注释中解释。存储为标记的联合。 “标签”指示这是一种表达。 “ Iex”是持有字段的联合。 如果IRExpr'e'具有等于Iex_Load的e.tag,则它是一个负载表达式,并且可以使用'e.Iex.Load。<fieldname>'访问这些字段。

	struct _IRExpr {
	   IRExprTag tag;
	   union {
	      /* 仅用于Vex内的模式匹配。不应出现在vex之外 */
	      struct {
	         Int binder;
	      } Binder;
	
	/*在guest state的固定偏移量处读取来宾寄存器。ppIRExpr输出:GET:<ty>(<offset>),例如GET:I32(0)*/
	struct {
	         Int    offset;    /*guest state的偏移 */
	         IRType ty;        /* 要读取值的类型 */
	      } Get;
	
	/*
	        在guest state下以非固定偏移量读取来guest存器。这允许循环索引到guest state的一部分,这对于建模guest存器的身份直到运行时才知道的情况至关重要。一个例子是x87 FP寄存器堆栈。
	         要作为循环数组处理的guest state的一部分在IRRegArray'descr'字段中描述。它保存数组中第一个元素的偏移量、每个元素的类型和元素的数量。
	数组索引是相当间接地表示的,以一种使优化变得容易的方式:作为可变部分(“ix”字段)和恒定偏移量(“bias”字段)的总和。
	         由于索引是循环的,实际使用的数组索引计算为(ix+bias)%数组中的元素数。
	举个列子如下:
		(96:8xF64)[t39,-7]
	       描述一个由8个F64类型值组成的数组,第一个值的guest state偏移量为96。此数组的索引位置是(t39-7)%8。
	         正确地获得数组大小/类型是很重要的,因为IR优化会密切关注这些信息,以便在单独的GetI和PutI事件之间建立混叠/非混叠,后者用于确定何时可以重新排序等。输入不正确的信息将导致模糊的IR优化错误。*/
		ppIRExpr output: GETI<descr>[<ix>,<bias]
		                         eg. GETI(128:8xI8)[t1,0]
		 struct {
		         IRRegArray* descr; /*  被视为循环的guest state的一部分*/
		         IRExpr*     ix;    /* 索引到数组的可变部分 */
		         Int         bias;  /* 索引到数组的固定部分*/
		      } GetI;
	
	/*临时变量的存储
		ppIRExpr output: t<tmp>, eg. t1*/
	struct{
		ITRemp tmp;   /*临时变量号*/
		}RdTmp;
	
	/*四元运算。*/
	ppIRExpr output: <op>(<arg1>, <arg2>, <arg3>, <arg4>),
	                      eg. MAddF64r32(t1, t2, t3, t4)
	 struct {
	        IRQop* details;
	      } Qop;
	
	/*三元运算。
	ppIRExpr output: <op>(<arg1>, <arg2>, <arg3>),
	                      eg. MulF64(1, 2.0, 3.0)
	*/
	 struct {
	        IRTriop* details;
	      } Triop;
	
	/*二元运算。
	ppIRExpr output: <op>(<arg1>, <arg2>), eg. Add32(t1,t2)
	*/
	 struct {
	         IROp op;          /* op-code   */
	         IRExpr* arg1;     /* operand 1 */
	         IRExpr* arg2;     /* operand 2 */
	      } Binop;
	
	
	/*一元运算:ppIRExpr output: <op>(<arg>), eg. Neg8(t1)*/
	struct {
	         IROp    op;       /* op-code */
	         IRExpr* arg;      /* operand */
	      } Unop;
	
	/*加载内存数据——一个普通的加载,而不是一个链接的加载。加载链接(和存储条件)由IRStmt.LLSC表示,因为加载链接有副作用,因此在语义上不是有效的IRExpr。
	ppIRExpr output: LD<end>:<ty>(<addr>), eg. LDle:I32(t1)*/
	 struct {
	         IREndness end;    /* Endian-ness of the load */
	         IRType    ty;     /* Type of the loaded value */
	         IRExpr*   addr;   /* Address being loaded from */
	      } Load;
	
	/*常量表达式
	ppIRExpr output: <con>, eg. 0x4:I32*/
	struct {
	         IRConst* con;     /* The constant itself */
	      } Const;
	
	/*函数调用
	‘cee'中的'name’是函数名字,主要是为了更好的打印效果,'cee'中的'addr'保存函数地址。
	‘args' 是以NULL作为终结符的数字。IRType,表示参数类型。必须和函数调用相匹配。
	函数调用必须满足以下几个条件
		-没有副作用,函数结果只取决于传递过去的参数
		-它可能不会查看或修改任何guest state,因为这样会隐藏插入器的guest state转换
		-它可能无法访问guest内存,因为这会隐藏来自检测程序的guest内存事务
		-它不能假定参数是按特定顺序计算的。未指定求值顺序。
	原则上,允许arg向量包含一个IRExpr_VECRET(),尽管不是IRExpr_BBPTR()。但是,目前没有要求clean helper调用能够返回V128或V256值。因此这是不允许的。
	ppIRExpr output: <cee>(<args>):<retty>
	                      eg. foo{0x80489304}(t1, t2):I32*/
	 struct {
	         IRCallee* cee;    /* 调用的函数. */
	         IRType    retty;  /* 返回类型. */
	         IRExpr**  args;   /* 表达式向量. */
	      }  CCall;
	
	/*三元if-then-else运算符。如果cond不为零,则返回iftrue,否则返回iffalse。请注意,它是严格的,即在所有情况下都会对iftrue和iffalse进行评估。
	ppIRExpr output: ITE(<cond>,<iftrue>,<iffalse>),
	                         eg. ITE(t6,t7,t8)
	*/
	struct {
	         IRExpr* cond;     /* Condition */
	         IRExpr* iftrue;   /* True expression */
	         IRExpr* iffalse;  /* False expression */
	      } ITE;
	   } Iex;
};




[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-3-31 09:31 被wwzzww编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (3)
雪    币: 0
活跃值: (638)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2020-4-29 11:39
0
雪    币: 977
活跃值: (435)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
mark   感谢分享
2020-6-15 10:59
0
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
mark
2020-6-15 14:51
0
游客
登录 | 注册 方可回帖
返回
//