'push imm'如何编码?

时间:2012-07-02 09:40:23

标签: assembly x86 nasm intel

<< Intel 64和IA-32架构软件开发人员手册卷2B:指令集参考,N-Z>表示:

| 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'不匹配。

  3. 请帮帮我!

    ======测试==

        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'
    

3 个答案:

答案 0 :(得分:6)

手册错了。 (顺便说一下,这不是唯一的错误)

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

编辑:实际上,我的手册版本说的是正确的:

  

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

所以在64位模式下,这意味着“推动qword,从立即扩展的标志”。

答案 1 :(得分:4)

编辑:下面的文字是错误的w.r.t.立即数。

以下是它的工作方式......

无论操作数大小是多少,在64位模式下,只能使用push将堆栈指针前进2或8个字节,并在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字节值的任何扩展名。

当你说push qword 12时,NASM似乎有点宽容。但是如果您使用的值不能表示为带符号的32位整数,它会发出警告,例如push qword 0x80000000push qword 2147483648push 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 imm8的操作码push imm16。这不可能是正确的。无论操作数大小前缀如何,字节操作数都保持字节操作数。只有“字”操作数可以扩展或缩减为双字和四字操作数。这就是它总是如此,一对操作相同指令的操作码,一个操作字节操作数,另一个操作(q / d)字操作数和操作数大小前缀会影响“字”的“字性”操作数。 64位模式下push word 12的正确编码应为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. 设计人员试图减少未对齐的堆栈错误

答案 2 :(得分: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