没有合适的资源?快使用搜索试试~ 我知道了~
接上揭密代码结构国外翻译
资源详情
资源评论
资源推荐
附录二:识别编译后的算术操作
This appendix explains the basics of how arithmetic is implemented in assembly
language, and demonstrates some basic arithmetic sequences and what they look like
while reversing. Arithmetic is one of the basic pillars that make up any program,
along with control flow and data management. Some arithmetic sequences are plain
and straightforward to decipher while reversing, but in other cases they can be
slightly difficult to read because of the various compiler optimizations performed.
本章介绍基本的算术操作是怎样在汇编语言中实现的一些基础知识,并演示一
些可能在逆向工程中经常遇到的基本的算术操作的实现指令流。算术操作和控
制流、数据管理一起构成了解决任何问题的支柱。在逆向工程中,某些算术操
作指令流的意思是显而易见的,但要解读出另一些经过了编译器优化处理后的
算术操作指令流就显得比较困难了。
This appendix opens with a description of the basic IA-32 flags used for arithmetic
and proceeds to demonstrate a variety of arithmetic sequences commonly found in
compiler-generated IA-32 assembly language code.
本附录从介绍最基本的IA-32标志位开始,然后介绍一些算术操作在IA-32编译
器生成的汇编语言中表现的代码
Arithmetic Flags
算术标志位
To understand the details of how arithmetic and logic are implemented in assembly
language, you must fully understand flags and how they’re used. Flags are used in
almost every arithmetic instruction in the instruction set, and to truly understand
the meaning of arithmetic sequences in assembly language you must understand the
meanings of the individual flags and how they are used by the arithmetic
instructions.
<Hannibal509@gmail.com>译
为了详细理解算术和逻辑指令是如何在汇编语言中实现的,你应该很好的理解
所有的标志位及其用途。几乎指令集中每一个算术指令都要用到标志位。而且
为了真正理解汇编语言中算术指令流的真正含义,你必须理解每一个标志位及
其是怎样被算术指令使用的。
Flags in IA-32 processors are stored in the EFLAGS register, which is a 32-bit
register that is managed by the processor and is rarely accessed directly by program
code. Many of the flags in EFLAGS are system flags that determine the current
state of the processor. Other than these system flags, there are also eight status
flags, which represent the current state of the processor, usually with regards
to the result of the last arithmetic operation performed. The following sections
describe the most important status flags used in IA-32.
IA-32体系结构的计算机中,所有的标志位都被集中存放在一个32位的“标志
位寄存器”中。该寄存器是直接由处理器进行管理,并极少被程序直接访问的。
“标志位寄存器”中的大多数标志位是系统标志位,它们的状态决定了处理器
的当前的状态。此外还有8个(非系统的)状态标志位,这8个标志位代表了处
理机当前的状态。通常这些标志位的标志着上一个算术操作的结果。下一节我
们介绍IA-32体系结构的计算机中最重要的状态寄存器。
The Overflow Flags (CF and OF)
溢出标志位(CF或者OF)
The
carry flag
(CF) and
overflow flag
(OF) are two important elements in
arithmetical and logical assembly language. Their function and the differences
between them aren’t immediately obvious, so here is a brief overview.
进位标志位(CF)和溢出标志位(OF)是在算法和逻辑汇编语言中两个重要的
元素。它们之间的功能上区别不是那么显而易见,所以下面我们简单介绍一下。
The CF and OF are both overflow indicators, meaning that they are used to notify
the program of any arithmetical operation that generates a result that is too large
in order to be fully represented by the destination operand. The difference between
the two is related to the data types that the program is dealing with.
CF和OF都是溢出指示器,这就是说这两个标志位的作用是:通知程序或算术指
令,其执行后得到的结果太大了,无法记录在目标操作数中。这两个标志位使
用上的区别在于CF是针对无符号数的,而OF是针对有符号数的。
Unlike most high-level languages, assembly language programs don’t explicitly
specify the details of the data types they deal with. Some arithmetical instructions
such as ADD (Add) and SUB (Subtract) aren’t even aware of whether the operands
they are working with are signed or unsigned because it just doesn’t matter—the
binary
result is the same. Other instructions, such as MUL (Multiply) and DIV
(Divide) have different versions for signed and unsigned operands because
multiplication and division actually produce different binary outputs depending
on the exact data type.
不像高级语言那样,汇编语言程序员不必显式的指明和关心当前处理的数据是
什么数据类型的。一些算术指令如:ADD、SUB也不关心操作数到底是有符号数
还是无符号数,因为这对指令执行的结果毫无影响——二进制结果是一样的。
但另一些指令如MUL、DIV对有符号数和无符号数有不同的版本——因为这时不
同的数据类型会对指令执行的结果有影响。
One area where signed or unsigned representation always matters is overflows.
Because signed integers are one bit smaller than their equivalent-sized unsigned
counterparts (because of the extra bit that holds the sign), overflows are triggered
differently for signed and unsigned integers. This is where the carry flag and the
overflow flag come into play. Instead of having separate signed and unsigned
versions of arithmetic instructions, the problem of correctly reporting overflows
is addressed by simply having two overflow flags: one for signed operands and one
for unsigned operands. Operations such as addition and subtraction are performed
using the same instruction for either signed or unsigned operands, and such
instructions set both groups of flags and leave it up to the following instructions
to regard the relevant one.
有符号数和无符号数操作必须面对的一个相同的问题就是溢出,但是因为有符
号数要比同样长度的无符号数少一个bit(这个bit用于表示符号),所以有符
号数和无符号数的溢出条件是不一样的。所以我们就需要两个溢出标志位OF和
CF,一个来表示有符号数(第7位)的溢出(OF)一个来表示无符号数(第8位)
的溢出(CF)(设操作数是8位的)。这样在ADD或者是SUB指令针对有符号操作
数和无符号操作数就可以用一样的指令,一样的执行部件,一样的设置标志位
的方法来实现了。而判断是否溢出时就只要去看相应的标志位就可以了。
For example, consider the following arithmetic sample and how it affects the
overflow flags:
见下例,我们观察一下执行了下面的指令后,会对标志位产生什么样的影响:
mov ax, 0x1126 ; (4390 in decimal)
mov bx, 0x7200 ; (29184 in decimal)
add ax, bx
The above addition will produce different results, depending on whether the
destination operand is treated as signed or unsigned. When presented in hexadecimal
form, the result is 0x8326, which is equivalent to 33574—assuming that AX is
considered to be an unsigned operand. If you’re treating AX as a signed operand,
you will see that an overflow has occurred. Because any signed number that has the
most significant bit set is considered negative, 0x8326 becomes –31962. It is
obvious that because a signed 16-bit operand can only represent values up to 32767,
adding 4390 and 29184 would produce an overflow, and AX would wraparound to a
negative number. Therefore, from an unsigned perspective no overflow has occurred,
but if you consider the destination operand to be signed, an overflow has occurred.
Because of this, the preceding code would result in OF (representing overflows in
signed operands) being set and in CF (representing overflows in unsigned operands)
being cleared.
上面的加法指令因为目的操作数是不是有符号数而产生不同的结果。我们从头
来说:如果我们设AX中是一个无符号数,那么加法的结果应该是0x8326(十六进
制,即十进制的33574),但如果假设AX是一个有符号数,我们将到一个溢出的
结果。因为有符号数的最高位是用来表示正负的,所以0x8326就变成了-31962
了,这是因为一个16位的有符号数最多只能表示到32767,把4390与29184相加
就会产生溢出,于是AX中的数就变成一个负数了。所以执行上面的代码后,OF
将会被设成1(标志有符号数溢出),而CF将被清零(标志无符号数无溢出)。
The Zero Flag (ZF)
零标志位(ZF)
The zero flag is set when the result of an arithmetic operation is zero, and it
is cleared if the result is nonzero. ZF is used in quite a few different situations
in IA-32 code, but probably one of the most common uses it has is for comparing
two operands and testing whether they are equal. The CMP instruction subtracts
one operand from the other and sets ZF if the pseudo result of the subtraction
operation is zero, which indicates that the operands are equal. If the operands
are unequal, ZF is set to zero.
当算术操作的结果为0时ZF将置1;如果结果不为0,则ZF将被清零。ZF标志位在
IA-32汇编语言中有几种不同的用法,但最常用的一个用法大概就是比较两个操
作数并测试它们是否相等。如CMP指令进行一个将两个操作数相减的伪操作,并
设置ZF标志位。如果指令执行完毕后ZF为0则两个操作数相等,否则,两个操作
数不相等。
The Sign Flag (SF)
符号标志位(SF)
The sign flag receives the value of the most significant bit of the result
(regardless of whether the result is signed or unsigned). In signed integers this
is equivalent to the integer’s sign. Avalue of 1 denotes a negative number in the
result, while a value of 0 denotes a positive number (or zero) in the result.
符号标志位的作用是记录结果的最高有效位(不管是有符号数还是无符号数)。
对于有符号数其相当于记录了结果的正负(1表示结果是负数;0表示结果是正
数,或者是0)。
The Parity Flag (PF)
奇偶标志位(PF)
The parity flag is a (rarely used) flag that reports the binary parity of the lower
8 bits of certain arithmetic results. Binary parity means that the flag reports
the parity of the
number of bits set
, as opposed to the actual
numeric parity
of
the result. A value of 1 denotes an even number of set bits in the lower 8 bits
of the result, while a value of 0 denotes an odd number of set bits.
奇偶标志位(使用比较少)是用来记录指令运算结果的低8位的奇偶性的,它与
操作结果低8位的奇偶性正好相反:PF为1表示操作的结果低8位是偶数,反之这
是奇数。
Basic Integer Arithmetic
基本整型数操作
The following section discusses the basic arithmetic operations and how they are
implemented by compilers on IA-32 machines. I will cover optimized addition,
subtraction, multiplication, division, and modulo.
下面这一节讨论基本的算术操作以及它们是怎样在IA-32机器上实现的。我们将
看到加、减、乘、除以及模运算。
Note that with any sane compiler, any arithmetic operation involving two constant
operands will be eliminated completely and replaced with the result in the assembly
code. The following discussions of arithmetic optimizations only apply to cases
where at least one of the operands is variable and is not known in advance.
注意:对于任意一款健全的编译器来说,任何一个算术操作都必须包含两个常
量操作数的算术指令都会在编译阶段就被除去(计算出操作的结果,并用结果
代替该条指令),所以下面的讨论中,任意一个操作中都至少包括一个未知的
操作数。
Addition and Subtraction
加法和减法
Integers are generally added and subtracted using the ADD and SUB instructions,
which can take different types of operands: register names, immediate hard-coded
operands, or memory addresses. The specific combination of operands depends on the
compiler and doesn’t always reflect anything specific about the source code, but
one obvious point is that adding or subtracting an immediate operand usually
reflects a constant that was hard-coded into the source code (still, in some cases
compilers will add or subtract a constant from a register for other purposes,
without being instructed to do so at the source code level). Note that both
instructions store the result in the left-hand operand.
整型数的加法和减法是用ADD和SUB指令来实现的,这两条指令可以同时接受几
种不同类型的操作数:寄存器名,立即数或者是内存地址。经过编译器优化编
译以后,汇编指令与高级语言源代码中指令并不一定是一一对应的,但一个明
显的特征是:如果加、减法指令的操作数是一个立即数的话,那么它通常就会
对应源代码中的一个常数(当然有时编译器会为了一个其他的目的对一个寄存
器加上或减去一个常数(立即数),而对应的高级语言源代码却中没有相应的
指令(比如,你可以回忆一下附录一中的switch语句块的树实现))。另外请
注意,所以的IA-32指令中所有的操作结果都是存放在左边的操作数中的。
Subtraction and addition are very simple operations that are performed very
efficiently in modern IA-32 processors and are usually implemented in
straightforward methods by compilers. On older implementations of IA-32 the LEA
instruction was considered to be faster than ADD and SUB, which brought many
compilers to use LEA for quick additions and shifts. Here is how the LEA
instruction can be used to perform an arithmetic operation.
加、减法指令是可以由IA-32处理器有效处理的最简单的操作,并且通常编译器
是用直接方式实现的,在早期的IA-32的实现中,编译器还优先选择LEA指令来
实现快速的加法或移位操作。下面是LEA指令的一个例子
Lea ecx, DWORD PTR [edx+edx]
剩余24页未读,继续阅读
czf520
- 粉丝: 0
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0