2. 深入了解 prefix


上一页 返回目录 下一页

在 GPI(General-Purpose Instruction)指令里,Legacy Prefix 是在整个编码序列的最前部分,起了对内存操作数进行修饰补充作用。

 

1. Legacy prefix

1.1 legacy prefix 的作用

legacy prefix 主要有以下作用:


1.2 legacy prefix 分类

leagcy prefix 包括下面几类:

  1. operand size override prefix:66H --- 改变默认操作数大小
  2. address size override preifx:67H --- 改变默认操作数地址大小
  3. segment override prefix:改变 memory 操作数段选择子,包括:
  4. rep/repz prefix:F3H --- 串指字重复执行
  5. repnz prefix:F2H --- 串指字重复执行
  6. lock prefix: F0H --- LOCK

 

1.3 REX prefix 的作用


2. 指令系统的上下文环境

要彻底了解 prefix,必须要结合 3 个很重要的上下文环境:

  1. 指令本身的 default operand-sizedefault address-size 以及 effective operand sizeeffective address size
  2. assembler 编译器上文环境
  3. 当前 processor 的执行上下文环境。

在本节内容里将会根据上面三个环境进行讲解。

这里操作数是内存操作数。出现调整的情形,这是因为:

也就是说:指令编码因指令操作数的 operand size, address size 以及 segment 的不同而不同


3. 缺省和有效(default 与 effective)上下文环境

在 x86/x64 平台的指令系统里有两个很重要的概念:

缺省(default)概念

包括:缺省操作数大小以及缺省地址大小(default operand-sizedefault address-size)。

这里,我们说的“32 位”或者“16 位”的概念指的是:default operand size 是 32 位,或者 16 位。

在 64 位下,情况有些特殊
  • default address-size 是 64 位的
  • default operands-size 在大多数指令下是 32 位的,而部分指令下是 64 位的

指令的 default operand size 是由 CS.D 标志位来决定,这个 default operand size 可由 CS.D 标志位来改变:

缺省的 operand size 和 address size 可由 66H prefix 及 67H prefix 进行改写,经过改写后的 operand size 和 address size 是指令最终的 operand size 和 address size


有效(effective)概念

包括:有效的操作数大小以及有效地址大小(effective operand-sizeeffective address-size

模式
effective operand size
effective address size
实模式,保护模式,v8086 模式以及compatibility 模式
16, 32
16, 32
64-bit 模式
16, 32, 64
32, 64

在 64 位模式下,情况又有些特殊:在 64 位下支持 16 位,32 位以及 64 位的操作数大小。但是不支持 16 位的地址大小。

关于“default 与 effective”的更详细的论述,请见:default(缺省)与 effective(有效)一文

 

 

4. 调整操作数的大小(66H prefix - Operand Size Override)

4.1 Operand Size Override 行为

是指
    改变指令的 default operands size(缺省/默认操作数的大小),使它的 operand size 不再是 default operands size

基于这种需求,在指令编码中使用 66H prefix 来实现 operand size override ,例如:

    bits 16                ; 16 位代码

mov eax, ebx


    bits 32                ; 32 位代码

mov ax, bx

上面的代码两种情况下都需要使用 66H prefix 进行改写 operand size


4.2 66H prefix(Operand-Size Override prefix)

66H 字节这个 prefix 用来更改 operands size,当然只能在指令所支持的 effective operand-size 范围内进行调整。

66H 在 Opcode 表中就是一个 prefix,处理器在解码时识别它不是 Opcode

 

4.3 Operand Size Override 的规则

怎样进行 Override 以及 Override 什么? 都是有固定的规则的,这和 default operand size 以及 effective operand size 有紧密的关系

表 4.3.1

模式
default operand size
effective operand size
prefix
REX prefix
描述
实模式,保护模式,virtual-8086 模式,compatibility 模式
16
16
---
---
2 种 default operand size 下的情形
32
66H
32
16
66H
32
---
64-bit 模式
32
16
66H
---
64-bit 模式下的 2 种 default operand size 情形
32
---
---
64
---
REX.W = 1
64
16
66H
---
64
---

在 64-bit 模式下大多数指令 default operand size 是 32 位的,因此,可以有 3 种 effective operand size

表中:--- 表示无需 prefix,REX.W = 1 表示:调整到 64 位(REX.W = 0 它是使用 default operand size)

* 标注处的 default operand size = 64 只有少数的指令 default operand size 是 64 位,大部分指令的 default 是 32 位的。

  1. 实模式,保护模式,v8086 模式以及 compatibility 模式下

  2. 在 64-bit 模式下

在 64 位的 default operand size 下,effective operand size 只有 2 种:

因此:只能使用 66H prefix 改写为 16 位的操作数,不能改写为 32 位操作数。

 

4.4 为什么需要改变操作数大小?

原因前面已经提过,很简单:当 16 位代码下需要访问 32 位数据或者 32 位代码需要访问 16 位数据时。

    bits 16                ; 16 位代码

mov bx, cx                 ; 不需要进行 operand size override
mov eax, ebx               ; 需要进行 operand size override

上面代码所示,在 16 位模式下,上面的不需要 override,而下面一条指令则需要进行 override

4.5 看看几个例子

例 1: 在 16 位的 default operand size 下,指令: mov eax, ebx

由于在 16 位下,如果操作数的大小缺省是 16 位的,这条指令要访问 32 位的寄存器,那么需要使用 66H prefix 进行 operand size override

89 d8 ---> 66 89 d8   (使用 66H prefix 将 16 位 registers 改为 32 位 registers)


例 2: 在 32 位 default operand size 下,指令 mov ax, bx

由于在 32 位下,如果操作数的大小缺省是 32 位的,这条指令要访问 16 位寄存器,同样需要使用 66H prefix 进行调

89 d8 ---> 66 89 d8   (使用 66H prefix 将 32 位 registers 改为 16 位 registers)

 

表 4.5.1 (在实模式,保护模式,v8086 模式以及 compatibility 模式下适用

指令
default operand size
生成的指令编码
mov eax, ebx
16
66 89 d8
32
89 d8
mov ax, bx
16
89 d8
32
66 89 d8

上表是这 2 条指令分别在不同的 default operand size 下的指令编码情况

有些人或许会感到疑惑,为什么例 1例 2 编译器生成的结果是一样的。这就是 assembler 在不同的 编译上下文环境 译为相同的指令编码。

 

例3:在 32 位 default operand size 下,指令:mov ax, [11223344h]

在 Microsoft 的语法里,在内存操作数前一般要加指示字 word ptr,指明操作数的大小:mov ax, word ptr [11223344h] 实际上,在这条指令里,这个指示字不是必须的,加指示字只是比较直观。但有些情况是必须要加的,如:mov dword ptr [11223344h], 1

这条指令有两种译法:

使用 66H prefix 进行 operand size override

第 1 条 encode 中,a1 是 opcode,44332211 是 offset 值(我认为不属于 dispalcement,因为不是 ModRM 寻址提供的), 66 改变了缺省的操作数大小,将 32 位调整为 16 位。

第 2 条 encode 的 opcode 是 8b, ModRm 是 05, 而 44332211 是 dispalcement(需要 ModRM 寻址)。

 

例4: 在 16 位 default operand size 下,同样一条指令:mov eax, [11223344]

同样一样指令,但目的操作数大小不同,并且 assembler 编译上下文环境不同。

它两种译法为:

与例 3 所不同的是:这条指令增加了 67H prefix 来进行 address size override,使得可以保住 32 位的地址值

注意:在 16 位的 default operand size 下,缺省的 address size 也是 16 位的。但是,在上面的编码里,我们认为编译器没有实行截断地址值!

当编译器对 32 位的地址值进行截断时,可以有下表的指令编码示例。

表 4.5.2

指令
default operand size
生成的指令编码
备注
mov ax, [11223344h]
16
a1 44 33
地址值被截断为 16 位
32
66 a1 44 33 22 11
使用 66H 改写为 16 位操作数
mov eax, [11223344h]
16
66 a1 44 33
使用 66H,以及地址被截断为16位
32
a1 44 33 22 11
正常

这里必须有一点要认识到的:当在 16 模式下, 地址 [11223344h] 多数编译器会它截断只取低 16 位地址

那么:mov ax, [11223344h] 会被编译为 a1 44 33 (它不需 67H prefix 进行 address size override)

 

 

5. 编译上下文环境(assembler)

在一个汇编语言源文件里,需要给编译器一些编译指示:指示目标代码将生成是多少的?目标平台是什么?文件格式是什么?等等...

这个就编译上下文环境。

例如:
操作系统的引导初始化代码部分是 16 位的,现在绝大多数 OS 是 32 位的,因此,在当前系统下写引导代码,则需要求编译器编译为 16 位实模式代码。因此,你不得不写 16 位代码,编译器根据情况将 32 位操作和地址调整至 16 操作数和地址。但在大部分情况下,不需要作调整,直接生成 16 位代码即可。

 

5.1 生成多少位的机器指令

以 nasm 编译器为例,下面给出一些代码片断:

; *********************************************************
; * unreal_mode.asm for test unreal mode on x86           *
; *                                                       *
; * Copyright (c) 2009-2010                               *
; * All rights reserved.                                  *
; * mik(deng zhi)                                         *
; * visit web site : www.mouseos.com                      *
; * bug send email : mik@mouseos.com                      *
; *                                                       *
; *                                                       *
; * version 0.01 by mik                                   * 
; *********************************************************

%include "include\arch\x64.inc"         ; mouseOS 0.02 project


BOOT_SEG equ 0x7c00 

 
 bits 16

 org BOOT_SEG                   ; for int 19
 
start:
        cli

; A20 gate enable 
        FAST_A20_ENABLE
 
        sti
 
 mov ax, cs
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov sp, BOOT_SEG


; real mode  --->  protected mode
 
next: 
; next setup is enter proected mode
; the proected mode is temporary

; How do ?
; frist: disable all IRQs and NMI

        cli
        NMI_DISABLE               ; NMI disable


; second: load temp GDT into GDTR

        db 0x66                         ; adjust to 32-bit operand size  
 lgdt [GDT_LIMIT]          ; load temp GDT into gdtr
 
 

; third: enable proected mode
 
 mov eax, cr0
 bts eax, 0                     ; CR0.PE = 1
 bts eax, 1                     ; CR0.MP = 1
 mov cr0, eax                   ; enable protected mode


; fourth: far jmp proected mode code

 jmp dword code32_sel:code32_entry

 
 bits 32

; Now: entry 32bit protected mode, but paging is disable
;  So: memory address is physical address

code32_entry:
 mov ax, data16_sel
 mov ds, ax
 mov es, ax
 mov ss, ax
 mov esp, 0x7ff0

 mov di, 0
 mov si, protected_msg
 call printmsg

上面代码片断显示:在一个源文件中,使用 bits 16 指示 nasm 生成 16 位的代码,并且使用 bits 32 指示 nasm 生成 32 位代码。 还可以使用 bits 64 来生成 64 位代码。


5.2 在源代码中指定位模式

上面代码片断中,使用 bits 伪指令来指示 nasm 生成何种代码。

注意:

nasm 的职责是根据给它下达的 bits 命令进行相应的编译,但不管生成的代码需要放在哪里运行!

如下例子:

bits 16

    mov eax, ebx
    mov eax, [dword 0x11223344]

代码中使用 bits 16 指示生成 16 位机器编码。至于把它放在哪里(16位还是32位下)运行是程序员的职责。

00000000  6689D8            mov eax,ebx
00000003  6766A144332211    mov eax,[dword 0x11223344]

在第 2 条指令里,使用了 DWORD 指示字强调地址为 32 位。因此,编译器生成了 66H prefix67H prefix 进行 override

 

6. processor 当前执行上下文环境

processor 处于什么模式下,这是系统程序员需要考虑的问题,从而通过代码体现出来,编译器根据代码生成相应的代码。

也就是说:
从 processor 角度来看,它以什么模式来对机器指令进行解码



下面的表格所列:当前的 default operand size 是多少时,处理器将 69 8d 这条机器编码解析为什么指令:

机器指令
CS.D = 0 时
CS.D = 1 时
CS.L = 1 并且 CS.D = 0 时
69 8d
mov ax, bx
mov eax, ebx
mov eax, ebx

同一条机器指令,由于处理器运行在不同的默认操作数宽度下,指令的解码是不同的。但是只不同在于 operand size

 

7. 调整地址大小(67H prefix - Address Size Override)

当需要改变地址大小的时候,也需要使用 67H prefix 来进行调整。同样是在所支持的 effective address-size 范围内。

7.1 Address Size Override 行为

是指
    改变指令原来的 default address size(缺省/默认地址宽度),使它的 address size 不再是 default address size

7.2 67H prefix(address size override prefix)

指令中可以使用 67H 进行 address size override,同样 67H 不是 opcode,处理器在的解码时认为它是 prefix。


7.2 Address size override 规则

怎样进行 Override 以及 Override 什么? 都是有固定的规则的,这和 default address size 以及 effective address size 有紧密的关系


表 7.2.1

处理器模式
default address size
effective address size
prefix
实模式,保护模式,virtual-8086 模式,compatibility 模式
16
16
---
32
67H
32
16
67H
32
---
64-bit 模式
64
32
67H
64
---

与 Operand size override 规则一样,在 effective address size 范围里调整为另一个 address size 需要使用 67H prefix

在 64 位模式下 default address size 是 64 位,不能调整到 16 位地址。

 

7.3 为什么要调整地址大小

以 16 位模式为例,如果需要访问 64K 以上的地址,则需要使用 67H 将 16 位寻址模式改写为 32 位的寻址模式。

 

7.4 Address size override 的几个例子

例1:在 16 的缺省操作数下,mov dword ptr [eax+ecx*8+0x11223344], 0x12345678

由于在 16 位的 default operands sizedefault address size 下,但该指令使用 32 位 operand size 以及 32 位 address size

也就是说既要改写 default operand size 也要改写 default address size。所以,应加上 66H prefix 改写 operand-size,再加上 67H prefix 改写 address-size。

最终的 encode 为: 66 67 c7 84 c8 44 33 22 11 78 56 34 12



例2:在 32 位缺省操作数下,mov eax, dword ptr [11223344]

该指令的编码为: a1 44 33 22 11

------------------------------------

当我们进行手工改写时,加上 67H prefix 变为: 67 a1 44 33 22 11

那么此时,用 67H prefix 调整为 16 位地址,那么在汇编语句将变为: mov eax, dword ptr [3344]

结果是: 加了 67H prefix 之后,它的地址将被截断为 16 位。即地址:0x3344,多出 22 11 两个字节属下条指令边界了。

 

例3:在 32 位缺省操作数下,mov eax, dword ptr [bx + si + 0x0c]

很显然,这条汇编语句源操作数的地址是 16 位的。

由于 default address size 为 32 位,因此,需使用 67H prefix 将这个 32 位寻址模式调整 16 位寻址模式。

最终的 encodes 是: 67 8b 40 0c

40H 这个 ModRM 字节对应的 16 位寻址是: [bx + si + 0x0c]

----------------------------------

假如,将 67 8b 40 0c 这个机器码放在 16 位环境下执行,指令则变为: mov eax, dword ptr [eax + 0x0c]

这是由于使用了 67H 将 16 位的 default address size 改写 32 位的 address size 所产生的结果!

 

7.5 16 位寻址模式与 32 位寻址模式的区别

上面的 3 个例子显示了 16 位地址和 32 位地址的区别,主要来自 16 位的内存操作数寻址只支持 BX 与 BP 寄存器作为基址寄存器,SI 和 DI 寄存器作为变址寄存器,比 32 位的内存寻址少得多。

 

表7.5.1 assembler 在 32 位下和 16 位下的区别(assembler 编译上下文环境)

序号
指令
在 bits 32 下编译的结果
在 bits 16 下编译的结果
1 mov dword [eax + ecx * 8 + 0x11223344], 0x12345678 c7 84 c8 44 33 22 11 78 56 34 12 66 67 c7 84 c8 44 33 22 11 78 56 34 12
2* mov eax, dword [0x11223344] a1 44 33 22 11 66 a1 44 33
3 mov eax, dword [bx + si + 0x0c] 67 8b 40 0c 66 8b 40 0c

表1中显示的是在不同的编译上下文环境同一条指令产生的不同编码(例如,在 nasm 编译器使用 bits 16 和 bits 32 指示字)

注意:

  在第 2 条时,地址 [0x11223344] 在 16 位代码的编译环境中,不同的编译器可能会有不同的处理结果:

   大多数 assembler(编译器)会将 [0x11223344] 截断为 [0x3344]。

  ★ 但是,一个功能强大的,全面的 assembler 应该将 [0x11223344] 还原为 [0x11223344],产生的编码应是: 66 67 a1 44 33 22 11

  有关 16 位寻址模式和 32 位寻址模式,详细请参看 AMD 与 Intel 手册

 

7.6 67H prefix 的深层含义

当插入 67H prefix(address-size override)时,它根据处理器当前的 default operand/adderss size,内存寻址上产生相应的转变:

★ 当处理器运行在 16 位的 default address size 下,指示:将要使用 32 位地址。因此,内存寻址要用 32 位寻址模式。

★ 当处理器运行在 32 位的 default address size 下,指示:将要使用 16 位地址。因此,内存寻址要用 16 位寻址模式。

 

表2:处理器在 16 与 32 位的 default address size 下解析区别 (处理器执行上下文环境)

序号
指令编码 encods(机器指令)
default operand/address size = 32
default operand/address size = 16
1* c7 84 c8 44 33 22 11 78 56 34 12 mov dword ptr [eax + ecx * 8 + 0x11223344], 0x12345678 mov word ptr [si + 0x44c8], 0x2233
2* 66 67 c7 84 c8 44 33 22 11 78 56 34 12 mov word ptr [si + 0x44c8], 0x2233 mov dword ptr [eax + ecx * 8 + 0x11223344], 0x12345678
3 67 8b 40 0c mov eax, dword ptr [bx + si + 0x0c] mov ax, word ptr [eax + 0x0c]
4 8b 40 0c mov eax, dword ptr [eax + 0x0c] mov ax, word ptr [bx + si + 0x0c]

表2中显示在不同的执行上下文环境同一条机器指令编码产生的不同行为。

注意:

  ★ 第1条中,机器码:c7 84 c8 44 33 22 11 78 56 34 12 当处理器在 16 位 default operand/address size 下,只解析前面的 c7 84 c8 44 33 22

    剩下的 11 78 56 34 12 将被视为下一条指令。

  ★ 第2条中,机器码:66 67 c7 84 c8 44 33 22 11 78 56 34 12 当处理器在 32 位 default operand/address size 下,只解析前面的 66 67 c7 84 c8 44 33 22

    剩下的 11 78 56 34 12 将被视为下一条指令。

7.7 67H prefix 总结

  在汇编代码层面上,assembler 根据当前编译环境,将汇编语句生成相应的 encodes 决定是否使用 67H prefix

  在机器代码层面上,processor 根据当前执行环境来决定如何解析机器指令

 

 

8. 调整段选择子(Segment override)

对于大多数内存操数据来说,缺省以 DS 为段基址的。常见的是:DS 段基址,SS 段基址。

与 operand-size / address-size 一样,当需要调整缺省的 segment 时,需要使用相应的 segment override prefix


8.1 缺省 segment register

default opernads-sizedefault address-size 一样,segment registers 同样有 default segment register


8.1.1 基址寄存器(base register)

default segment register 与内存操作数中的 base register 相关。

例如:mov eax, dword ptr [eax] 指令中的 [eax] 操作数 eax 就是 base register

 

缺省寄存器规则:

 

8.2 Segment override 例子

foo:
    push ebp
    mov ebp, esp
    lea eax, [ebp - 0x0c]
   
    mov eax, dword ptr [eax]
    … 
    mov esp,ebp
    pop ebp
    ret

[ebp-0xc]:这个内存操作数缺省是基于 SS 段的

[eax]:这个内存操作数缺省是基于 DS 段的。

因此,对于上面的片段,[ebp - 0x0c] 是在 SS segment,即 stack 内。

[eax] 这个内存地址按照程序的意图是访问 stack 内的数据,所以,这里我将它调整为 stack segment

lea eax, [ebp - 0x0c]
mov eax, dword ptr ss:[eax]
(调整为访问 stack)

为什么一般程序都不会这么写呢? 那是因为,现代的操作系统都是采用平坦的内存模式,即:CS=SS=DS=ES,所以对 [eax] 这个操作数不需调整其结果是正确的。


8.2.1 [eax] 内存操作数进行调整为:mov eax, dword ptr ss:[eax]

产生的编码是: 36 8b 00

其中,36 也就是 SS segment-override prefix,将 DS 段调整为 SS 段。

 

8.3 Segment override prefix

当需要进行调整段寄存器时,就使用以上的 segment-override prefix。


8.4 在 64 位模式下的 segment override

在 64 位模式下,segmentation 管理已经被最大程度上的弱化,因此,当代码中进行 segment override 时,已经显得不重要了,可以有两个分段管理被保留下来:

它们被保留下来,令到程序中可以有额外的段式管理手段,因此,在代码中依然可以使用 fsgs 进行 segment override 操作

 

9. 通过 prefix 增强指令功能(F3 prefix 与 F2 prefix)

这些 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, 0x0c
    mov eax, [ebp+8]
    mov edi, eax
    mov esi, [ebp+0x0c]
    mov ecx, dword ptr [ebp+0x10]

move_loop:
    mov bl, byte ptr [esi]
    mov byte ptr [edi], bl
    inc esi
    inc edi
    dec ecx
    jnz move_loop
    
    mov esp, ebp
    pop ebp
    ret

上面的代码性能低下,是很死板的实现,优化的空间巨大。

x86 为串提供了相应的串操作指令(ins,outs,lods,stos,scas,cmps),对这些串指令提供 prefix 来增强优化这些指令。

 

9.1 rep prefix 或者 repz prefix(F3H prefix)

  可以看到 F3H prefix 有两重意义:rep 和 repz,但是使用的范围是不同的:

prefix 含义
使用范围
结束条件
rep
movs,lods,stos,ins,outs
ecx = 0
repz/repe
scas,cmps
ecx = 0 或 ZF = 0(比较结果不为零)

它们的使用范围和结束条件都不同。

 

9.1.1 rep 的意义

rep 重复执行指令一定的次数,这个次数在 ecx 中提供。

用伪代码描述为:

if (ecx != 0) {
    repeat do
    ecx = ecx - 1
}

首先判断 ecx 是否为 0,不为 0 则执行指令。

使用 rep 优化版本:

mov_char:
        ... ...
        mov edi, [ebp + 0x08]
        mov esi, [ebp + 0x0c]
        mov ecx, [ebp + 0x10]
        rep movsb
        ... ...
        ret

使用串指令 movsb 配合 rep prefix 进行复制,rep movsb 的编码为:



9.1.2 repz/repe 的意义

F3 prefix 另一层意义是 repe/repz,用于改变标志位的串操作:scas, cmps 指令

意思是:当比较结果相等(ZF=1)并且循环次数(ecx)不为 0 时进行重复操作。(重复的条件是:ZF = 1 & ecx <> 0

即:它的结束条件是:ecx = 0 或者 ZF = 0, 意思是:不相等时或者次数到了,就不重复执行指令

它的 c 伪码形式如下:

if (ecx != 0 && ZF = 1) {
    repeat do
    ecx = ecx - 1
}

常见运用一些跳过字符的逻辑上,如下面 C 代码,用于截除串前面空格:

char *trim(char *s)
{
    while (*s && *s == ' ')
        s++;

    return s;
}

reprepe/repz 是相同的 prefix,作用于不同的串指操作意义也不同:

当作用于不修改标志位的串指令时,它的意义是 rep,作用于修改标志位的串指令时,它的意义是 repz/repe


9.2 repne/repnz(F2H prefix)

F2H prefix 是表达 repne/repnz 意思是: 结果不相等(不为零)时循环。(重复条件是 ZF == 0 并且 ecx <> 0

结束条件是:ecx = 0 或者 ZF = 1 即:结果相等时退出循环。

同样也是用于改变标志位的串操作 scas 和 cmps

它的 c 伪码形式如下:

if (ecx != 0 && ZF = 0) {
    repeat do
    ecx = ecx - 1
}

常见一些查找字符的逻辑上,如下面 C 代码:

char *get_char(char *s, char c)
{
    while (*s && *s != c)
        s++;

    ret
}



10 附加功能(LOCK prefix)

   对于写内存的一些指令增加了锁地址总线的功能,这些写内存的指令如常见的 sub,add 等指令,通过 Lock prefix 来实现这功能,使用 Lock prefix 将会使 procesor 产生 LOCK# 信号锁地址总线

注意:
   Lock prefix 仅使用在一些对内存进行 read-modify-write 操作的指令上,如:add, sub, and 等指令。 否则,将会产生 #UD (无效操作码) 异常

如下指令所示:

lock add dword ptr [eax], 1

它的指令编码是:


F0: Lock prefix 锁地址总线。

上一页 返回目录 下一页


版权所有 mik 2008 - 2014