- 论坛徽章:
- 0
|
(接上)
2、增强指令功能
一些 prefix 对 Opcode 进行补充,增强指令的功能,优化指令执行,看下面这段 c 代码:
char *move_char(char *d, char *s, unsigned count)
{
char *p = d;
while (count--)
*d++ = *s++;
return p;
} |
这是典型的、经典的字符串复制c代码,对应以下类似的汇编代码:
move_char:
push ebp
mov ebp, esp
sub esp, 0xc
mov eax, [ebp+8]
mov edi, eax
mov esi, [ebp+0xc]
mov ecx, dword ptr [ebp+0x10]
move_loop:
mov bl, byte ptr [esi]
mov byte ptr [edi], bl
inc esi
inc edi
dec ecx
test ecx,ecx
jnz move_loop
mov esp, ebp
pop ebp
ret |
上面的代码性能低下,是很死板的实现,优化的空间巨大。
x86 为串提供了相应的串操作指令(ins,outs,lods,stos,scas,cmps),对这些串指令提供 prefix 来增强优化这些指令:
● F3: rep prefix 或 repe prefix
● F2: repne prefix
2.1、 rep prefix
重复进行串操作,仅应用于 ins,outs,movs,lods,stos 这些不改变标志位的串指令,结束条件是 ECX 为 0。
使用串操作及 rep prefix 上面的汇编代码可简单如下:
move_char:
… …
mov eax, [ebp+8]
mov edi, eax
mov esi, [ebp+0xc]
mov ecx, [ebp+0x10]
rep movsb
… …
rep movsb 的操作原理和上面的 C 代码一致,下面是伪码:
while (ecx != 0) {
c = ds:[esi];
es:[edi] = c;
esi = esi + 1
edi = edi + 1
ecx = ecx – 1;
} |
2.2、 repe prefix
F3 的另个 prefix 意思是 repe/repz,用于改变标志位的串操作:scas,cmps 意思是当相等(ZF=1)并且循环次数(ecx)不为 0 时进行重复操作。
结束条件是:ecx 为 0 或者 ZF 标志位为 0, 或者说是循环条件是(ecx 不为 0,并且 ZF 标志位为 1)
|
常见运用一些跳过字符的逻辑上,如下面 C 代码,用于截除串前面空格
char *trim(char *s)
{
while (*s && *s == ‘ ‘)
s++;
return s;
}
|
而用伪码表示为:
While (ecx != 0 and ZF = 1) {
Ecx = ecx – 1;
cmpsb
} |
rep 与 repe/repz 是相同的 prefix,作用不用体现在对串指操作上:
movsb 的 opcode 是 A4,scasb 的opcode 是 AE,对于下面的 encode:
F3 A4:这时 F3 prefix 是 REP, movsb 不改变标志位
F3 AE:这时 F3 prefix 是 REPZ, scasb 改变标志位
2.3、 repne/repnz prefix
F2:这个 prefix 是 repne/repnz,意思是:循环次数(ecx)不为 0 并且 ZF=0 时重复操作。结束条件是:ecx=0 或者 ZF=1 |
同样也是用于改变标志位的串操作 scas 和 cmps。
常见一些查找字符的逻辑上,如下面 C 代码:
char *get_c(char *s, char c)
{
while (*s && *s != c) s++;
return s;
}
|
而用伪码表示为:
While (ecx !=0 and ZF != 1) {
Ecx = ecx – 1;
cmpsb
}
|
3、 附加功能(LOCK)
对于写内存的一些指令增加了锁地址总线的功能,这些写内存的指令如常见的 sub,add 等指令,通过 Lock prefix 来实现这功能,使用 Lock prefix 将会使 processor 产生 LOCK# 信号锁地址总线
注意:
Lock prefix 仅使用在一些对内存进行 read-modify-write 操作的指令上,如:add, sub, and 等指令。 否则,将会产生 #UD (无效操作码) 异常 |
F0: Lock prefix 锁地址总线。 |
|