POP
从堆栈中弹出一个值
stableVMJITAOTinstruction
编码
| 操作码 | 指令 | Op/En | 64 位 | 兼容/传统 | 说明 |
|---|---|---|---|---|---|
8F /0 | POP r/m16 | M | 有效 | 有效 | 堆叠的弹出顶部为m16;增量为栈指针. |
8F /0 | POP r/m32 | M | 不可编码 | 有效 | 堆叠的弹出顶部为m32;增量为栈指针. |
8F /0 | POP r/m64 | M | 有效 | 不可编码 | 弹出堆栈顶部为 m64; 递增堆栈指针。 无法编码 32 位操作大小 。 |
58+ rw | POP r16 | O | 有效 | 有效 | 堆叠的弹出顶部为r16;增量为栈指针. |
58+ rd | POP r32 | O | 不可编码 | 有效 | 堆叠的弹出顶部为r32;增量为栈指针. |
58+ rd | POP r64 | O | 有效 | 不可编码 | 弹出堆栈顶部为 r64; 递增堆栈指针。 无法编码 32 位操作大小 。 |
1F | POP DS | ZO | 无效 | 有效 | 堆叠的弹出顶部为DS;增量为栈指针. |
07 | POP ES | ZO | 无效 | 有效 | 堆叠的弹顶进入ES;增量栈指针. |
17 | POP SS | ZO | 无效 | 有效 | 堆叠的顶部为SS;增量为栈指针. |
0F A1 | POP FS | ZO | 有效 | 有效 | 堆栈的弹出顶部为FS;增量栈指针乘以16位. |
0F A1 | POP FS | ZO | 不可编码 | 有效 | 堆栈的弹出顶部为FS;增量栈指针乘32位. |
0F A1 | POP FS | ZO | 有效 | 不可编码 | 堆栈的弹出顶部为FS;增量栈指针乘以64位. |
0F A9 | POP GS | ZO | 有效 | 有效 | 堆栈的弹出顶部为GS;增量为栈指针乘以16位. |
0F A9 | POP GS | ZO | 不可编码 | 有效 | 堆栈的弹出顶部为GS;增量栈指针乘以32位. |
0F A9 | POP GS | ZO | 有效 | 不可编码 | 堆栈的弹出顶部为GS;增量栈指针乘以64位. |
操作数编码
每个模式对应上表 Op/En 列的一个取值,说明各操作数按书写顺序分别编码在指令的哪个字段,以及指令对它是读、是写还是两者兼有。
M
modrm.rmescrituraModRM 字节的 r/m 字段(第 2-0 位);当 mod 字段要求时,还包括 SIB 字节和位移
O
opcode.regescritura操作码字节自身的低三位
实测开销
正在从 arch-data 加载实测数据...
说明
将值从堆栈顶部加载到指定位置的目标操作数(或明确操作码),然后加增栈指针. 目标操作数可以是通用寄存器,内存位置,也可以是片段寄存器.
地址和操作数大小的确定和使用如下:
- 地址大小 。 当前代码框描述符中的 D 旗决定默认地址大小; 可能是
被指令前缀( 67H) 覆盖 。
地址大小仅在写入内存中的 目标操作数 时使用.
- 操作数大小 (英语). 当前代码框描述符中的 D 旗决定默认 操作数大小; 它可能
被指令前缀(66H或REX.W)所覆盖.
操作数大小(16,32或64位)决定栈指针递增的金额(2,4或8).
- 堆叠地址大小 。 除64位模式外,当前堆栈框描述符中的B旗决定
栈指针的大小(16或32位);在64位模式中,栈指针的大小总是64位.
堆栈地址大小决定了栈指针在内存中从堆栈读取以及栈指针增量时的宽度. (如上所述,栈指针增量的金额由操作数大小确定. )
如果目标操作数是某一段注册DS,ES,FS,GS,或SS,则装入注册的值必须是有效的段选择子. 在 保护模式 中,将一个 段选择子 弹出到一个分区自动寄存器 -
从逻辑上将与该段选择子相关的描述信息加载到片段的隐藏(阴影)部分,并导致选择者和描述信息被验证(见下文"操作"部分).
NULL值(000-0003)可跳入DS,ES,FS或GS注册,而不会引起一般的保护故障. 然而,任何后续试图引用一个其对应的片段寄存器被装入NULL值的片段,都会引起一般保护例外(#GP). 在这种情况下,没有发生内存引用,区段寄存器的保存值是NULL.
POP 指令无法将一个值弹出到 CS 寄存器中 。 要从堆栈装入 CS 寄存器,请使用 RET 指令 。
如果 ESP 寄存器用作在内存中处理 目标操作数 的基数寄存器,则 POP 指令在递增 操作数 寄存器后计算 ESP 的有效地址. 对于ESP通过POP指令将0H包裹到0H的16位堆栈的情况,由此产生的内存书写位置是处理器家庭特异性的.
POP ESP指令在旧堆栈顶部的数据写入目的地之前,会增加栈指针(ESP).
用 POP 指令装入 SS 注册 抑制或抑制一些调试例外,并抑制下列指令边界上的中断. (抑制在发送例外或执行下一个指令后结束. ) 这种行为允许一个栈指针与下一个指令(POP ESP)一起加载到ESP的寄存器中,然后一个事件才能交付. 见7.8.3节,"交换堆栈时的异常和中断",载于Intel(R)64和IA-32架构软件开发者手册,第3A卷. Intel建议软件使用LSS指令将SS寄存器和ESP加载在一起.
在64位模式中,使用REX前缀的形式为REX.R允许访问额外的注册(R8-R15). 当在64位模式下,使用32位的操作数的持久性有机污染物不能编码,持久性有机污染物到DS,ES,SS无效. 参见本节开头的汇总图,用于编码数据和限制.
行动
IF StackAddrSize = 32
THEN
IF OperandSize = 32
THEN
DEST := SS:ESP; (* Copy a doubleword *)
ESP := ESP + 4;
ELSE (* OperandSize = 16*)
DEST := SS:ESP; (* Copy a word *)
ESP := ESP + 2;
FI;
ELSE IF StackAddrSize = 64
THEN
IF OperandSize = 64
THEN
DEST := SS:RSP; (* Copy quadword *)
RSP := RSP + 8;
ELSE (* OperandSize = 16*)
DEST := SS:RSP; (* Copy a word *)
RSP := RSP + 2;
FI;
FI;
ELSE StackAddrSize = 16
THEN
IF OperandSize = 16
THEN
DEST := SS:SP; (* Copy a word *)
SP := SP + 2;
ELSE (* OperandSize = 32 *)
DEST := SS:SP; (* Copy a doubleword *)
SP := SP + 4;
FI;
FI;
Loading a segment register while in protected mode results in special actions, as described in the following listing.
These checks are performed on the segment selector and the segment descriptor it points to.
64-BIT_MODE
IF FS, or GS is loaded with non-NULL selector;
THEN
IF segment selector index is outside descriptor table limits
OR segment is not a data or readable code segment
OR ((segment is a data or nonconforming code segment)
AND ((RPL > DPL) or (CPL > DPL))
THEN #GP(selector);
IF segment not marked present
THEN #NP(selector);
ELSE
SegmentRegister := segment selector;
SegmentRegister := segment descriptor;
FI;
FI;
IF FS, or GS is loaded with a NULL selector;
THEN
SegmentRegister := segment selector;
SegmentRegister := segment descriptor;
FI;
PREOTECTED MODE OR COMPATIBILITY MODE;
IF SS is loaded;
THEN
IF segment selector is NULL
THEN #GP(0);
FI;
IF segment selector index is outside descriptor table limits
or segment selector's RPL CPL
or segment is not a writable data segment
or DPL CPL
THEN #GP(selector);
FI;
IF segment not marked present
THEN #SS(selector);
ELSE
SS := segment selector;
SS := segment descriptor;
FI;
FI;
IF DS, ES, FS, or GS is loaded with non-NULL selector;
THEN
IF segment selector index is outside descriptor table limits
or segment is not a data or readable code segment
or ((segment is a data or nonconforming code segment)
and ((RPL > DPL) or (CPL > DPL))
THEN #GP(selector);
FI;
IF segment not marked present
THEN #NP(selector);
ELSE
SegmentRegister := segment selector;
SegmentRegister := segment descriptor;
FI;
FI;
IF DS, ES, FS, or GS is loaded with a NULL selector
THEN
SegmentRegister := segment selector;
SegmentRegister := segment descriptor;
FI;受影响的旗帜
None.
异常
保护模式
#GP(0) | 如果尝试用 NULL 分区选择器加载 SS 注册器。 如果目的操作器处于不可写入的分区中。 如果内存操作器的有效地址位于 CS, DS, ES, FS, 或 GS 分区限制之外, 如果使用 DS, ES, FS, 或 GS 注册器访问内存并包含 NULL 分区选择器 。 |
#GP(selector) | 如果 段选择子 指数在描述表限制之外。 如果正在装入SS 寄存器, 而 段选择子 的 RPL 和 片段描述器的 DPL 则不等于 CPL 。 如果正在装入SS 寄存器, 而片段指向的是一个不可写入的数据片段。 如果正在装入DS、ES、FS 或 GS 寄存器, 片段指的不是数据或可读代码片段。 如果正在装入DS、ES、FS 或 GS 寄存器, 而片段指的是一个数据或非格式代码片段, 但 RPL 和 CPL 都大于 DPL 。 |
#SS(0) | 如果当前堆栈顶部不在堆栈段之内。 如果 内存操作数 有效地址在 SS 段限制之外 。 |
#SS(selector) | 如果正在装入党卫军登记册,而指向的路段没有标记。 |
#NP | 如果正在装入DS,ES,FS或GS寄存器,而指向的片段没有标记. #PF(fault-code) 如果发生页面错误. |
#AC(0) | 如果在当前特权级别为3时引用不匹配的内存,并启用对齐检查. |
#UD | 如果使用 LOCK 前缀 。 |
实地址模式
#GP | 如果内存操作数的有效地址在CS,DS,ES,FS或GS段限制之外. |
#UD | 如果使用 LOCK 前缀 。 |
虚拟 8086 模式
#GP(0) | 如果内存操作数的有效地址位于CS,DS,ES,FS,或GS段限制之外. #PF(fault-code) 如果发生页面错误. |
#AC(0) | 如果在启用对齐检查时进行了不匹配的内存引用 。 |
#UD | 如果使用 LOCK 前缀 。 |
兼容模式
| 与保护模式例外相同. |
64 位模式
#GP(0) | 如果内存地址是非冠状的. |
#SS(0) | 如果堆栈地址是非冠状的. |
#GP(selector) | 如果描述符在描述符表限制之外。如果正在装入FS或GS寄存器,且指向的片段不是数据或可读代码片段。如果正在装入FS或GS寄存器,指向的片段是数据或不符合规则的代码片段,但RPL和CPL都大于DPL。 |
#AC(0) | 如果在启用对齐检查时进行了不匹配的内存引用. #PF(fault-code) 如果发生 页面错误 时. |
#NP | 如果正在装入FS或GS登记册,而指向的段没有标记。 |
#UD | 如果使用 LOCK 前缀。 如果正在装入 DS, ES, 或 SS 寄存器 。 |