它们的含义在下面的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;
};