2

<< Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2B: Instruction Set Reference, NZ >> 说:

| Opcode* | Instruction | Op/En | 64-Bit Mode | Compat/Leg Mode | Description |
|      6A | PUSH imm8   | C     | Valid       | Valid           | Push imm8.  |
|      68 | PUSH imm16  | C     | Valid       | Valid           | Push imm16. |
|      68 | PUSH imm32  | C     | Valid       | Valid           | Push imm32. |

# cat -n test.asm

 1  bits 64
 2
 3  push byte 12
 4  push word 12
 5  push dword 12
 6  push qword 12
 7

# nasm test.asm

 test.asm:5: error: instruction not supported in 64-bit mode
  1. 为什么5号线是非法的?我认为它与“PUSH imm32”匹配。

  2. 为什么第 6 行是合法的?它与“PUSH imm8/PUSH imm16/PUSH imm32”中的任何一个都不匹配。

请帮帮我!

======测试======

    I think that the Intel manual is right, the 'push imm' 
    instructions do have three encoding form:
    Form 1: 6a XX
    Form 2: 66 68 XX XX 
    Form 3: 68 XX XX XX XX

    What we are arguing is the implemental specific behavior of the NASM.

    In NASM 2.04rc1(the above example I given):
    1. The 'byte' in 'push byte imm' direct the NASM use the Form 1, 
       no matter how long the imm given in the instruction it is, the imm
       was trunked to a byte in final machine code. 
    2. The 'word' in 'push word imm' direct the NASM use the Form 2,
       no matter how long the imm given in the instruction it is, the imm 
       was trucked or zero-extended to a word in final machine code.
    3. The 'qword' in 'push dword imm' direct the NASM use the Form 3,
       no matter how long the imm given in the instruction it is, the imm 
       was trucked or zero-extended to a dword in final machine code.
       Note: the 'qword' in the instruction but 'dword' in final machine
       code, which made us confused.
    4. if none of 'byte', 'word', 'qword' is given, the NASM use the From 3.

请参见以下示例:

# cat -n push.asm
1  bits 64
2
3  push byte 0x21
4  push byte 0x4321
5
6  push word 0x4321
7  push word 0x654321
8
9  push qword 0x654321
10
11  push 0x21
12  push 0x4321
13  push 0x654321
14  push 0x87654321
15  push 0xa987654321
16
# nasm -v
NASM version 2.04rc1 compiled on Feb 21 2009
# nasm push.asm -o push.bin
push.asm:4: warning: signed byte value exceeds bounds
push.asm:7: warning: word data exceeds bounds
# ndisasm -b 32 push.bin // 'ndisasm -b 64 push.bin' not works right in this version of NASM.
00000000  6A21              push byte +0x21
00000002  6A21              push byte +0x21
00000004  66682143          push word 0x4321
00000008  66682143          push word 0x4321
0000000C  6821436500        push dword 0x654321
00000011  6821000000        push dword 0x21
00000016  6821430000        push dword 0x4321
0000001B  6821436500        push dword 0x654321
00000020  6821436587        push dword 0x87654321
00000025  6821436587        push dword 0x87654321

In newer NASM, the behavior changes:
(1) 'push 0x21' was encoded to '6A21' in NASM 2.10.01,
    while '6821000000' in NASM 2.04rc1; 
(2)'push dword 0x654321' in 64 bit mode was allowed 
    in NASM 2.10.01 and encoded to '6821436500'
4

3 回答 3

7

说明书错了。(顺便说一句,这不是唯一的错误)

在 64 位模式下,没有 32 位推送。push是少数不带 REX.W 前缀提升为 64 位的指令之一,您不能将其降级。

编辑:实际上,我的手册版本说得对:

推送符号扩展的 imm32。堆栈指针按堆栈指针的大小递减。

因此,在 64 位模式下,这意味着“推送一个 qword,从立即数扩展符号”。

于 2012-07-02T10:04:10.673 回答
4

编辑:下面的文字是错误的。

这是它的工作原理...

无论操作数大小如何,在 64 位模式下,您只能使用 a 将堆栈指针推进 2 或 8 个字节,push并在因此分配的空间中写入 16 位或 64 位值。

因此,您不能推送 8 位寄存器或 32 位寄存器,因为它们不会进行零或符号扩展。但是您可以推送 16 位或 64 位寄存器。

对于立即数,它有点不同。

push imm8(操作码 6Ah 后跟 imm8)将首先将 8 位立即操作数符号扩展为 64 位,然后压入所得的 8 字节值。

push imm32(操作码 68h 后跟 imm32)将首先将 32 位立即操作数符号扩展为 64 位,然后压入生成的 8 字节值。

push imm16(操作数大小前缀 66h,操作码 6Ah 后跟 imm16)将不带任何扩展名的 16 位立即操作数作为 2 字节值推送。

当你说 NASM 似乎有点宽容push qword 12。但如果您使用不能表示为有符号 32 位整数的值,例如push qword 0x80000000orpush qword 2147483648或,它将发出警告push qword -2147483649

This is the relevant piece of documentation:
ELSE IF SRC is immediate byte
  THEN TEMP ← SignExtend(SRC); (* extend to operand size *)
ELSE IF SRC is immediate word (* operand size is 16 *)
  THEN TEMP ← SRC;
ELSE IF SRC is immediate doubleword (* operand size is 32 or 64 *)
  THEN
    IF operand size = 32
      THEN TEMP ← SRC;
      ELSE TEMP ← SignExtend(SRC); (* extend to operand size of 64 *)
FI;

现在,我的 NASM 版本(2011 年 7 月 15 日编译的 2.09.10)实际上并没有针对push dword 12. 如果您的确实如此,那是一个错误。

看起来我在 NASM 中发现了一个错误。它组装push word 12成 66h、6Ah、0Ch。IOW,它使用push imm8for的操作码push imm16。这不可能。无论操作数大小前缀如何,字节操作数仍然是字节操作数。只有“字”操作数可以扩展或缩减为双字和四字操作数。一直都是这样,同一条指令的一对操作码,一个对字节操作数进行操作,另一个对(q/d)字操作数进行操作,操作数大小前缀会影响“字”的“字性”操作数。push word 1264 位模式下的正确编码应该是 66h、68h、0Ch、0h。

第 5 行是非法的,因为在 64 位模式下您不能压入 32 位操作数。您只能推送 64 位操作数(push byte 12有效地push byte-sign-extended-to-qword 12)或 16 位操作数。看一个解释操作的伪代码push

IF in 64-bit mode (* stack-address size = 64 *)
  THEN
    IF operand size = 64
      THEN
        RSP ← RSP − 8;
        Memory[RSP] ← TEMP; (* Push quadword *)
      ELSE (* operand size = 16 *)
        RSP ← RSP − 2;
        Memory[RSP] ← TEMP; (* Push word *)
FI;

具体原因我说不出来,但有两个:

  1. 以这种方式实现它很方便
  2. 设计者试图降低未对齐堆栈错误的可能性
于 2012-07-02T10:07:21.237 回答
1
    I think that the Intel manual is right, the 'push imm' 
    instructions do have three encoding form:
    Form 1: 6a XX
    Form 2: 66 68 XX XX 
    Form 3: 68 XX XX XX XX

    What we are arguing is the implemental specific behavior of the NASM.

    In NASM 2.04rc1(the above example I given):
    1. The 'byte' in 'push byte imm' direct the NASM use the Form 1, 
       no matter how long the imm given in the instruction it is, the imm
       was trunked to a byte in final machine code. 
    2. The 'word' in 'push word imm' direct the NASM use the Form 2,
       no matter how long the imm given in the instruction it is, the imm 
       was trucked or zero-extended to a word in final machine code.
    3. The 'qword' in 'push dword imm' direct the NASM use the Form 3,
       no matter how long the imm given in the instruction it is, the imm 
       was trucked or zero-extended to a dword in final machine code.
       Note: the 'qword' in the instruction but 'dword' in final machine
       code, which made us confused.
    4. if none of 'byte', 'word', 'qword' is given, the NASM use the From 3.

请参见以下示例:

# cat -n push.asm
1  bits 64
2
3  push byte 0x21
4  push byte 0x4321
5
6  push word 0x4321
7  push word 0x654321
8
9  push qword 0x654321
10
11  push 0x21
12  push 0x4321
13  push 0x654321
14  push 0x87654321
15  push 0xa987654321
16
# nasm -v
NASM version 2.04rc1 compiled on Feb 21 2009
# nasm push.asm -o push.bin
push.asm:4: warning: signed byte value exceeds bounds
push.asm:7: warning: word data exceeds bounds
# ndisasm -b 32 push.bin // 'ndisasm -b 64 push.bin' not works right in this version of NASM.
00000000  6A21              push byte +0x21
00000002  6A21              push byte +0x21
00000004  66682143          push word 0x4321
00000008  66682143          push word 0x4321
0000000C  6821436500        push dword 0x654321
00000011  6821000000        push dword 0x21
00000016  6821430000        push dword 0x4321
0000001B  6821436500        push dword 0x654321
00000020  6821436587        push dword 0x87654321
00000025  6821436587        push dword 0x87654321
于 2012-07-03T02:53:24.093 回答