汇编语言的条件移动数据指令
cmovx source, destination
cmov指令基于EFLAGS寄存器做条件判断,用于条件判断的位如下:
EFLAGS寄存器的位 | 数据类型指示 | 数据类型描述 |
---|---|---|
CF | Carry flag | A mathematical expression has created a carry or borrow |
OF | Overflow flag | An integer value is either too large or too small |
PF | Parity flag | The register contains corrupt data from a mathematical operation |
SF | Sign flag | Indicates whether the result is negative or positive |
ZF | Zero flag | The result of the mathematical operation is zero |
指令对 | 指令描述 | EFLAGS寄存器条件 |
---|---|---|
CMOVA/CMOVNBE | 大于/不小于等于 | (CF or ZF) = 0 |
CMOVAE/CMOVNB | 大于等于/不小于 | CF=0 |
CMOVNC | Not carry | CF=0 |
CMOVB/CMOVNAE | 小于/不大于等于 | CF=1 |
CMOVC | Carry | CF=1 |
CMOVBE/CMOVNA | 小于等于/不大于 | (CF or ZF) = 1 |
CMOVE/CMOVZ | 等于/zero | ZF=1 |
CMOVNE/CMOVNZ | 不等于/zero | ZF=0 |
CMOVP/CMOVPE | Parity/parity even | PF=1 |
CMOVNP/CMOVPO | Not parity/parity odd | PF=0 |
指令对 | 指令描述 | EFLAGS寄存器条件 |
---|---|---|
CMOVGE/CMOVNL | 大于等于/不小于 | (SF xor OF)=0 |
CMOVL/CMOVNGE | 小于/不大于等于 | (SF xor OF)=1 |
CMOVLE/CMOVNG | 小于等于/不大于 | CMOVLE/CMOVNG |
CMOVO | Overflow | OF=1 |
CMOVNO | Not overflow | OF=0 |
CMOVS | Sign (negative) | SF=1 |
CMOVNS | Not sign (non-negative) | SF=0 |
movl value, %ecx
cmp %ebx, %ecx
cmova %ecx, %ebx
* 注意:Remember that in AT&T syntax, the order of the operands in the CMP and CMOVA instructions are reversed from the Intel documentation. This can be confusing. *
指令 | 指令描述 |
---|---|
XCHG | Exchanges the values of two registers, or a register and a memory location |
BSWAP | Reverses the byte order in a 32-bit register |
XADD | Exchanges two values and stores the sum in the destination operand |
CMPXCHG | Compares a value with an external value and exchanges it with another |
CMPXCHG8B | Compares two 64-bit values and exchanges it with another |
xchg operand1, operand2
bswap operand1
# swaptest.s – An example of using the BSWAP instruction
.section .text
.globl _start
_start:
nop
movl $0x12345678, %ebx
bswap %ebx
movl $1, %eax
int $0x80
# bswap %ebx执行后,$ebx的值为:0x78563412
xadd source, destination
cmpxchg source, destination
cmpxchg8b destination
# bubble.s - An example of the XCHG instruction
.section .data
values:
.int 105, 235, 61, 315, 134, 221, 53, 145, 117, 5
.section .text
.globl _start
_start:
movl $values, %esi
movl $9, %ecx
movl $9, %ebx
loop:
movl (%esi), %eax
cmp %eax, 4(%esi)
jge skip
xchg %eax, 4(%esi)
movl %eax, (%esi)
skip:
add $4, %esi
dec %ebx
jnz loop
dec %ecx
jz end
movl $values, %esi
movl %ecx, %ebx
jmp loop
end:
movl $1, %eax
movl $0, %ebx
int $0x80
#示例代码是排序算法——冒泡法,同下面的高级语言代码
for(out = array_size-1; out>0, out--)
{
for(in = 0; in < out; in++)
{
if (array[in] > array[in+1])
swap(array[in], array[in+1]);
}
}
pushx source
x表示数据大小(l,32位;w,16位)
# 示例
pushl %ecx # puts the 32-bit value of the ECX register on the stack
pushw %cx # puts the 16-bit value of the CX register on the stack
pushl $100 # puts the value of 100 on the stack as a 32-bit integer value
pushl data # puts the 32-bit data value referenced by the data label
pushl $data # puts the 32-bit memory address referenced by the data label
popx destination
x表示数据大小(l,32位;w,16位)
# 示例
popl %ecx # place the next 32-bits in the stack in the ECX register
popw %cx # place the next 16-bits in the stack in the CX register
popl value # place the next 32-bits in the stack in the value memory location
指令 | 描述 |
---|---|
PUSHA/POPA | Push or pop all of the 16-bit general-purpose registers |
PUSHAD/POPAD | Push or pop all of the 32-bit general-purpose registers |
PUSHF/POPF | Push or pop the lower 16 bits of the EFLAGS register |
PUSHFD/POPFD | Push or pop the entire 32 bits of the EFLAGS register |
PUSHA指令将16位压栈的顺序是:DI, SI, BP, BX, DX, CX, 和最后的 AX ;
PUSHAD指令的压栈顺序和PUSHA一样 ;
POPA和POPAD指令的出栈顺序是上面的反序 ;
POPF和POPFD指令对,依赖处理器的操作模型,如果处理器运行在受保护模型,EFLAGS寄存器中的所有非预留标识位可以被修改,除了VIP, VIF, 和 VM 标识位,VIP 和 VIF 标识位会被清掉,VM标识位不能被修改 ;
PUSH和POP不是唯一的栈操作指令,你可以使用ESP作为内存地址指针,来存取数据;
通常,不只是使用ESP寄存器自己,很多程序会拷贝ESP寄存器的值到EBP;通常汇编程序过程会使用EBP指向指定过程的栈底,指令通过EBP来访问保存在栈中的参数 ;
内存访问是一个比较慢的功能,影响处理器性能;写高性能的汇编程序,最好是尽量内存访问,越少越好 ;如果可能的话,进行保持变量在寄存器中;寄存器访问很快,是处理器的最佳选择;这是处理数据最快的方式 ;如果将所有应用程序数据放到寄存器中不可能实现,你应该试着去优化程序的内存访问 ,因为处理器会使用数据缓存,有顺序的访问内存,会增加缓存命中 ,因为内存块会一次性读入缓存;
另外大多数处理器(包括IA-32平台)已优化为从特殊的缓存块读写内存,从汇编程序的.data数据块定义的数据的起始位置开始,Pentium 4处理器,缓存块的大小是64位,如果你定义的数据元素跨过64位块的边界,就需要两次缓存操作去读写内存数据元素 ;Intel建议按以下规则定义数据:
写汇编程序时,在定义.data数据块时,尽量把相同大小的数据元素放在一起 ;如果有不规则大小的数据元素,如字符串和buffers,将它们放到.data数据块的最后 ;
gas assembler supports the .align directive,将数据元素定义在指定的边界内,17章会详细讲解