【问题标题】:Matching the intel codes to disassembly output将英特尔代码与反汇编输出相匹配
【发布时间】:2020-09-13 20:04:58
【问题描述】:

我开始使用英特尔参考页面来查找和了解操作码(而不是在 SO 上询问所有内容)。我想确保我的理解没有问题,并就基本 asm 程序和 intel 指令代码之间的输出提出一些问题。

这是我必须将各种mov 指令与rax-ish 寄存器进行比较的程序(有没有更好的方式来表示“rax”及其 32- 16- 和 8- 位组件?):

.globl _start
_start:
    movq $1,    %rax    # move immediate into 8-byte rax (rax)
    movl $1,    %eax    # move immediate into 4-byte rax (eax)
    movw $1,    %ax     # move immediate into 2-byte rax (ax)
    movb $1,    %al     # move immediate into 1-byte rax (al)
    mov $60,    %eax
    syscall

它的反汇编如下:

$ objdump -D file

file:     file format elf64-x86-64


Disassembly of section .text:

0000000000400078 <_start>:

  400078:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
  40007f:   b8 01 00 00 00          mov    $0x1,%eax
  400084:   66 b8 01 00             mov    $0x1,%ax
  400088:   b0 01                   mov    $0x1,%al

  40008a:   b8 3c 00 00 00          mov    $0x3c,%eax
  40008f:   0f 05                   syscall

现在,匹配来自MOV 的英特尔代码,复制到这里:

我能够协调以下四个指令:

  1. mov $0x1,%al --> b0 01
    ,英特尔声明代码是 b0 [+ 1 byte for value] 用于 1 字节立即移动。
  2. mov $0x1,%eax --> b8 01 00 00 00
    ,英特尔声明代码为 b8 [+ 4 bytes for value] 用于 1 字节立即移动。
  3. mov $0x1,%ax --> 66 b8 01 00
    ,英特尔声明代码是 b8 而不是 66 b8
  4. mov $0x1,%rax48 --> c7 c0 01 00 00 00
    N/A,仅限 32 位指令。未列出。

由此,我与此相关的问题是:

  • 为什么mov $0x1,%ax 不匹配?
  • 64-bit 代码是否有相同的表,或者建议的查找方法是什么?
  • 最后,当寄存器发生变化时,代码如何调整?例如,如果我想将一个值移动到%ebx%r11。您如何计算“代码调整”,就像在此查找表中所示,它仅提供(我认为?)eax 用于“注册示例代码”的注册。

【问题讨论】:

  • 这些条目让您决定使用操作数大小前缀 (66) 还是不获取 32 位和 64 位模式下的 16 位操作数大小,或者 32 位操作数 - 16 位模式下的大小。 66 是前缀而不是操作码。 48 是 W=1 的 REX 前缀。再次,查找前缀后面的操作码。
  • 另外,对于 64 位,不要再看旧版本的英特尔手册了。 felixcloutier.com/x86/mov 是从当前版本的英特尔 PDF 中提取的。或者,由于您需要了解手册条目的额外信息,只需阅读英特尔的实际 PDF,包括第 2 卷中的介绍章节。 stackoverflow.com/tags/x86/info中的链接和更多内容@
  • @PeterCordes 哦,那好多了,谢谢你的链接(它还支持在 html 中搜索,其他版本不支持)。
  • 也相关:How many ways to set a register to zero? 提到了 32 位或 64 位寄存器的 mov 的 3 种不同形式。

标签: assembly x86 x86-64 intel machine-code


【解决方案1】:

您缺少更改以下指令含义的前缀“操作码”(概念)。第 2 卷,IA32 manual 的第 2.1.1 和 2.2.1 节涵盖了这一点。从 2.1.1 我们得到:

操作数大小覆盖前缀使用 66H 编码(66H 也用作某些强制前缀 说明)。

因此 66 前缀将操作数大小从默认的 32 位更改为 16 位。因此,mov $1,%ax(16 位)与 mov $1,%eax(32 位)相同,只是前缀为 66

最后一种情况(mov $1, %rax)实际上是使用了不同的指令

REX.W + C7 /0 io    MOV r/m64, imm32      Move imm32 sign extended to 64-bits tor/m64.

这里我们将一个常量移动到任何寄存器而不是 A —— 指令大一个字节,但允许将一个 32 位 immed 移动到一个 64 位寄存器,因此只需要一个 4 字节常量而不是一个8 字节一(因此最终比等效的 48 b8 01 00 00 00 00 00 00 00 小 3 个字节

【讨论】:

  • 谢谢,能否请您链接到说明的部分,以便我可以阅读更多相关信息?除了66,还有哪些可用的前缀?
  • rex.w 是什么意思?据我所知,它似乎被忽略了(那为什么要列出呢?)
  • @carl.hiass rex.w 将操作数大小更改为 64 位。
  • @carl.hiass 否。REX 前缀仅存在于 64 位模式中。 W 更改操作数大小,RXBregister 操作数、base 的寄存器号提供了一个额外的位,和 index,即它们将寄存器编号 0-7 的含义从 rax、rcx、rdx、rbx、rsp、rbp、rsi 和 rdi 转换为 r8、r9、r10、r11、r12 、r13、r14 和 r15 设置时。
  • @carl.hiass 检查目录。有一章是关于指令格式的。应该在第 2 卷的开头。从那里开始。下载分卷的手册版本可能会有所帮助,因为与组合卷文件一样大的 PDF 文件可能会使您的 PDF 查看器不堪重负。
猜你喜欢
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 2021-03-16
  • 2011-02-14
  • 2012-10-22
相关资源
最近更新 更多