x86-64 (AMD64) 架构中是否有默认操作数大小?

2023-11-29

这是关于 x86-64 (AMD64) 架构中操作数大小覆盖前缀的问题。

这是一堆汇编指令(nasm)及其编码;经过new我的意思是 r8, ..., r15 寄存器:

                                                                   67: address-size override prefix
                                                                   |
                                                                   |  4x: operand-size override prefix
                                                                   |  |
   ;   Assembler                   ; | Dst operand | Src operand | -- --
       mov      eax,ecx            ; | 32-bit      | 32-bit      |       89 C8     |
       mov      r8d,ecx            ; | 32-bit new  | 32-bit      |    41 89 C8     |
       mov      eax,r9d            ; | 32-bit      | 32-bit new  |    44 89 C8     |
       mov      r8d,r9d            ; | 32-bit new  | 32-bit new  |    45 89 C8     |
       mov      rax,rcx            ; | 64-bit      | 64-bit      |    48 89 C8     |
       mov      r8,rcx             ; | 64-bit new  | 64-bit      |    49 89 C8     |
       mov      rax,r9             ; | 64-bit      | 64-bit new  |    4C 89 C8     |
       mov      r8,r9              ; | 64-bit new  | 64-bit new  |    4D 89 C8     |

       lea      eax,[ecx]          ; | 32-bit      | 32-bit      | 67    8D 01     |
       lea      r8d,[ecx]          ; | 32-bit new  | 32-bit      | 67 44 8D 01     |
       lea      eax,[r9d]          ; | 32-bit      | 32-bit new  | 67 41 8D 01     |
       lea      r8d,[r9d]          ; | 32-bit new  | 32-bit new  | 67 45 8D 01     |
       lea      rax,[rcx]          ; | 64-bit      | 64-bit      |    48 8D 01     |
       lea      r8,[rcx]           ; | 64-bit new  | 64-bit      |    4C 8D 01     |
       lea      rax,[r9]           ; | 64-bit      | 64-bit new  |    49 8D 01     |
       lea      r8,[r9]            ; | 64-bit new  | 64-bit new  |    4D 8D 01     |

       push     rax                ; |             | 64-bit      |       50        |
       push     r8                 ; |             | 64-bit new  |    41 50        |

通过研究这些指令以及其他寄存器的相同指令,我得出以下结论。 “旧”寄存器和“新”寄存器之间存在配对。非详尽地:

   AX <--> R8
   CX <--> R9
   DX <--> R10
   BX <--> R11
   BP <--> R13 

忽略大小前缀,指令字节并不引用特定的寄存器,而是引用寄存器对。例如:字节 89 C8 表示从源(ecx、rcx、r9d 或 r9)到目标(eax、rax、r8d 或 r8)的 mov 指令。鉴于操作数必须同时为 32 位或 64 位宽,因此有八种合法的可能组合。操作数大小覆盖前缀(或不存在)指示那些组合中的哪一个是预期的组合。例如,如果前缀存在并且为 44,则源操作数必须是 32 位新寄存器(在本例中然后折叠为 r9d),并且目标必须是 32 位旧寄存器(此处发送 eax 信号)。

我可能不完全正确,但我想我明白了它的要点。那么操作数大小覆盖前缀所覆盖的事实是,如果没有它们,指令将使用 32 位“旧”操作数。

但可以肯定的是,有一些东西让我无法理解,否则:谈论“默认操作数大小为 64 位的 x86-64 版本”有什么意义(例如here)?

或者有没有一种方法,在 64 位机器上运行,将默认操作数大小设置为 32 或 64,如果是这样,并且如果我的程序适当地设置机器,我会看到不同的编码?

另外:什么时候会使用 66H 操作数大小覆盖前缀?


是的,在 64 位机器代码中,大多数指令的默认操作数大小为 32 位,64 位堆栈和跳转/调用指令,以及 64 位loop and jrcxz。 (默认地址大小是 64 位,所以add eax, [rdi]是一个 2 字节指令,没有前缀。)不,默认值是不可更改的,你不能有 2 字节add rax, rdx.

64 位模式下的操作数大小编码

  • 64 位操作数大小由 REX.W 表示(0x4?高位设置在低半字节中,48..4f)。对于默认为其他内容的操作码,清除 W 位的 REX 前缀永远无法将操作数大小覆盖为 32 位。 (喜欢push)
  • 16 位操作数大小由一个信号表示0x66前缀,例如imul ax, [r8], 123
  • 8 位操作数大小使用不同的操作码。 (8086 有 8 位和 16 位操作数大小;8 位操作数大小的操作码从那时起就没有变化。8086 的 16 位操作数大小的操作码的默认值与模式和前缀相关。)

(在其他模式下,没有REX,并且66将其设置为非默认值。)

有趣的事实:loop and jrcxz被覆盖通过地址大小前缀而不是操作数大小隐式使用 ECX 而不是 RCX。 IIRC,这是有道理的,因为分支的操作​​数大小属性会影响它是否将 EIP 截断为 IP。

例如,上面那些 NASM 语法示例的 GNU .intel_syntax 反汇编。

objdump -drwC -Mintel foo
  401000:       6a 7b                   push   0x7b
  401002:       66 6a 7b                pushw  0x7b
  401005:       03 07                   add    eax,DWORD PTR [rdi]
  401007:       66 03 07                add    ax,WORD PTR [rdi]
  40100a:       48 03 07                add    rax,QWORD PTR [rdi]
  40100d:       66 41 6b 00 7b          imul   ax,WORD PTR [r8],0x7b

请注意,imul 示例使用“高”寄存器,因此它需要一个 REX 前缀来表示 R8,而不需要一个 66 前缀来表示 16 位操作数大小。 .W 位是not设置在 rex 前缀中,它是0x41 not 0x49.

同时拥有 REX.W 和 a 是没有意义的0x66字首。在这种情况下,REX.W 前缀似乎“获胜”。单步执行66 48 05 40 e2 01 00 data16 add rax,0x1e240在 i7-6700k (Skylake) 上的 Linux GDB 中,单步使 RIP 指向整个指令的末尾(并将完整的立即数添加到 RAX),而不是将其解码为add ax, 0xe240并使 RIP 指向 4 字节立即数的中间。 (A66该操作码的前缀长度会发生变化,就像大多数具有 32 位立即数的操作码一样,它会变成 16 位。看https://agner.org/optimize/回复:LCP 停止运行。)

我让 NASM 发出它o16 add rax, 123456。 REX 前缀通常是正常的并且可以使用66前缀,例如编码add r8w, [r15 + r12*4],需要在 REX 的低半字节中设置所有其他 3 位。


  • 32-bit address大小由一个信号表示0x67前缀,例如add eax, [edx].

当然可以combined与操作数大小的东西,完全正交。

通常 32 位地址大小仅适用于Linux x32 ABI(长模式下的 ILP32 可节省指针密集型数据结构上的缓存占用空间)您可能希望从指针中截断高位垃圾,以确保地址数学正确换行以保留在低 4GiB 中,即使使用 32 位负数也是如此。

  401012:       67 03 04 ba             add    eax,DWORD PTR [edx+edi*4]

在其他模式下,67将地址大小设置为非默认值。 16 位地址大小也意味着 ModRM 字节的 16 位解释,因此仅[bx|bp + si|di]允许,没有 SIB 字节,以允许 32 / 64 位寻址的灵活性。


模式和默认设置

不,在 64 位模式下无法更改默认值。由 CS(或任何其他方法)选择的 GDT 条目中的不同位并不重要。 AFAIK,该表在https://en.wikipedia.org/wiki/X86-64#Operating_modes是模式和默认操作数/地址大小的可能组合的完整列表。

只有一组设置允许 64 位操作数大小。即使在任何传统模式下也不可能有 16 位操作数、32 位地址大小的组合。

从硬件复杂性的角度来看,这是有一定道理的。它需要支持的不同组合越多,CPU 中本已复杂且耗电的部分可能涉及的晶体管就越多。

(虽然默认stack推入/弹出隐式使用的地址大小由 SS 选择器 IIRC 独立选择。所以我认为你可以使用正常的 32 位模式add eax, [edx]是 2 个字节,除了使用 push/pop/call/retss:sp代替ss:esp。我从来没有尝试过设置。)


请注意,16 位 AX 对应于 16 位 R8W,而 RAX 和 R8 是通过 REX 前缀区分的对。


在汇编源代码中,没有默认值,它必须由寄存器隐含或显式指定。

除了一些具有push/pop默认值的汇编器,或者一些对其他情况有默认值的糟糕汇编器,包括GNU汇编器,例如add $1, (%rdi)默认为 dword,仅在最新版本中出现警告。 GAS 在模棱两可时出错mov,奇怪的是。 clang 的内置汇编器更好,在任何不明确的操作数大小上都会出错。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

x86-64 (AMD64) 架构中是否有默认操作数大小? 的相关文章

  • elf .rel.text 部分中 R_386_32/R_386_PC32 的含义

    为了理解重定位的概念 我编写了一个简单的 chk c 程序 如下所示 1 include
  • x86-64 Linux 中不再允许使用 32 位绝对地址?

    64 位 Linux 默认使用小内存模型 将所有代码和静态数据置于 2GB 地址限制以下 这确保您可以使用 32 位绝对地址 旧版本的 gcc 对静态数组使用 32 位绝对地址 以便节省相对地址计算的额外指令 然而 这不再有效 如果我尝试在
  • 如何调试 iOS 应用程序在启动时崩溃,仅在程序集文件中设置断点

    我遇到了当前正在开发的应用程序的问题 问题是应用程序在启动时在后台运行一段时间后崩溃 并且仅在这种情况下 在应用程序被杀死时启动应用程序不会导致调试器或手机崩溃 无论是否进行调试 在后台启动应用程序大约 5 10 分钟都不会导致崩溃 在后台
  • 这段汇编语言代码是什么意思?

    我是一名学生 刚刚开始学习汇编语言 为了更好地理解它 我只是用 C 写了一个简短的代码并将其转换为汇编语言 奇怪的是我有点听不懂 代码是 include
  • 在 x86 程序集中将整数打印到控制台

    当我在 16 位汇编中添加两个值时 将结果打印到控制台的最佳方法是什么 目前我有这个代码 CODE START mov ax 1 put 1 into ax add ax 2 add 2 to ax current value mov ah
  • 汇编-符号标志和奇偶校验标志

    我不明白什么时候设置标志标志 什么时候设置奇偶校验 据我所知 符号标志表示运算结果的符号 0表示正数 1表示负数 那么为什么在下一个代码中 mov al 5 sub al 124 SF为零 结果是负数 关于PF 为什么a和b中设置了PF a
  • 取消的分支与常规分支有何不同?

    特别是对于 SPARC Assembly 取消的分支与常规分支有何不同 我一直认为 当我需要填充分支指令的 nop 延迟槽时 需要取消分支指令 但是 我认为我在这一部分上是不正确的 因为您可以在不取消分支的情况下填充 nop 如果不采用分支
  • CALL指令是否总是将EIP指向的地址压入堆栈?

    x86架构中函数调用时是否存在返回地址不入栈的情况 No CALL根据定义 将在跳转到目标地址之前将返回地址压入堆栈 该返回地址是EIP or RIP sizeof call instruction 通常为 5 个字节 英特尔 64 和 I
  • 汇编基础知识:输出寄存器值

    我刚刚开始学习汇编语言 我已经陷入了 在屏幕上显示存储在寄存器中的十进制值 的部分 我使用 emu8086 任何帮助将不胜感激 model small Specifies the memory model used for program
  • 尝试使用 x86 程序集 GNU GAS 在数组索引处赋值时出现错误

    我在用x86GNU 与 GCC 的程序集 并尝试实现相当于以下内容的程序集c c int x 10 x 0 5 但是 当我尝试运行 使用命令 a out 我的汇编代码如下 第一次编译后gcc filename s 错误Segmentatio
  • 近调用/跳转表并不总是在引导加载程序中工作

    一般问题 我一直在开发一个简单的引导加载程序 并在某些环境中偶然发现了一个问题 在这些环境中 此类指令不起作用 mov si call tbl SI Call table pointer call call tbl Call print c
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以
  • 两个基本的 ANTLR 问题

    我正在尝试使用 ANTLR 来获取简单的语法并生成汇编输出 我在 ANTLR 中选择的语言是 Python 许多教程看起来非常复杂或详细阐述与我无关的事情 我真的只需要一些非常简单的功能 所以我有两个问题 将值从一个规则 返回 到另一规则
  • 汇编8086监听键盘中断

    我有与此完全相同的问题 边画边听键盘 https stackoverflow com questions 13970325 8086 listen to keyboard while drawing 但第一个答案 接受的答案 只听键盘一次
  • 页面错误陷阱的成本

    我有一个应用程序 它定期 每 1 或 2 秒后 通过分叉自身来获取检查点 因此 检查点是原始进程的一个分支 它一直保持空闲状态 直到原始进程发生某些错误时被要求启动 现在我的问题是fork的写时复制机制的成本有多大 每当原始进程写入内存页面
  • 使用 Easy 68K (68000) 组装范围内的随机数

    我正在使用 Easy 68K 模拟器创建一个简单的黑杰克游戏 需要使用随机数来分配牌 我的牌必须在 2 到 11 的范围内 我似乎每次都得到相同的数字 但它不在我预期的范围内 我的卡值需要以 D3 结束 因此我有以下随机数代码 CLR L
  • 弹出 x86 堆栈以访问函数 arg 时出现分段错误

    我正在尝试链接 x86 程序集和 C 我的C程序 extern int plus 10 int include
  • 从 exe 文件中获取汇编级代码?

    我当时正在做linux汇编编程 在过去的几天里我已经转而学习windows汇编编程 我在用ml作为我的汇编器和golink作为我的链接器 我有我的汇编代码并已获得我的exe从中 现在我需要取回它的十六进制 xff xab x55等等 在li
  • 使用 NEON 优化 Cortex-A8 颜色转换

    我目前正在执行颜色转换例程 以便从 YUY2 转换为 NV12 我有一个相当快的函数 但没有我预期的那么快 主要是由于缓存未命中 void convert hd uint8 t orig uint8 t result uint32 t wi
  • 阴影空间示例

    EDIT 我接受了下面的答案 并添加了我自己的代码的最终修订版 希望它向人们展示影子空间分配的实际示例 而不是更多的文字 编辑 2 我还设法在 YouTube 视频 所有内容 的注释中找到了一个调用约定 PDF 的链接 其中有一些关于 Li

随机推荐

  • 如何在块循环中使用 PHPExcel 库确定文件结尾?

    使用 PHPExcel 库 我尝试迭代大约 1500 行 每行大约有 25 列 我正在使用这段代码 取自PHPExcel 运行内存为 256 512 和 1024MB Create a new Reader of the type defi
  • Eclipse:以编程方式创建首选项页面

    我正在尝试以编程方式创建首选项页面 我需要使用首选项页面而不在plugin xml 中定义首选项页面扩展点 我非常接近解决方案 我能够加载页面并在应用程序第一次加载时保存值 我的代码的核心是 PreferenceManager pmngr
  • 使用 VBA 创建具有不同计数的数据透视表

    我正在尝试使用 Excel 2013 VBA 创建一个数据透视表 并将 DISTINCT COUNT 作为值字段 我知道 如果您手动创建数据透视表 则必须选中 将此数据添加到数据模型 复选框 以便为值数据透视字段提供不同的计数选项 但我不知
  • Laravel 5.8:Homestead 重启后尚未设置门面根

    所以我正在尝试进入 Laravel 这是我第一次使用 Vagrant 所以这是我的问题 我已经通过Laravel 家园介绍并设置我的开发框 一切似乎都正常工作 我确实看到了 Laravel 默认应用程序 当结束这一天时 我已经停止了本地流浪
  • 仅初始化部分功能一次

    我有一个很小的函数 我想初始化一次 例如 void SomeFunc static bool DoInit true if DoInit CallSomeInitCode DoInit false The rest of the funct
  • 无法更改模型生成器选项

    我试图让 symfony 使用一个名为的自定义类jsDoctrineRecord代替sfDoctrineRecord对于它的模型 这是重写类的代码
  • C# 中调整系统图标大小

    我想用SystemIcons Warning但它对于我的需要来说太大了 我想调整它的大小 我努力了 Icon sizedIcon new Icon SystemIcons Warning new Size 10 10 但它不起作用 图标保持
  • 将图像 src 数据:转换为 Uint8Array

    我想使用 异食癖图书馆 用于调整图像大小 但它要求我提供一个 Uint8Array 并且我只有一个带有 src data image jpeg base64 9j 4AAQ 我不知道如何将其变成 Uint8Array 有什么想法吗 Than
  • 防止将 master 中的文件与 Git 合并

    In 另一个问题建议使用 gitattributes为了保持文件跟踪但不合并到不同的分支中 但我下面的用例似乎不起作用 mkdir git cd git git init echo B gt b txt git add b txt git
  • HTML5:其他标签内有效标签的参考

    不久前我正在使用w3c 验证器对于 HTML5 我正在尝试用一个标签来替换已弃用的
  • Python pandas - 在groupby之后过滤行

    例如 我有下表 index A B 0 0 0 1 0 8 2 0 8 3 1 5 4 1 3 分组后按A 0 index A B 0 0 0 1 0 8 2 0 8 1 index A B 3 1 5 4 1 3 我需要的是从每个组中删除
  • 在 x64 中调用绝对地址

    我无法弄清楚这一点 我可以做出这样的指令 它工作没问题 call ffffdd80d60e4000 但我该如何将其转换为字节呢 我查看了内存中的指令并显示了奇怪的东西 例如 0xe8 0x00 0x40 0x0e 0xd6 我唯一能识别的是
  • 如何正确地为数据结构中的图像设置动画而不出现 ConcurrentModificationException

    对于那些讨厌阅读长问题的人 获取下面的完整代码 运行它 点击SPACE几次 你会得到一个ConcurrentModificationException 简单的问题 你如何解决它 问题是试图删除一个Fireball当它退出屏幕时从列表中删除
  • 在 MySQL 监视器中阅读 MySQL 手册?

    Problem 有效阅读MySQL手册 Error mysql gt create database plastronics gt ERROR 1007 HY000 Can t create database plastronics dat
  • 如何对比两组变量(在 SAS 中)

    数据如下 ID X1 X2 X3 Z1 Z2 Z3 对于每个 ID 考虑两组变量 X1 X2 X3 and Z1 Z2 Z3 that X和Z的数量可以相同或不同 它们也可能有缺失值 每组中的变量值都是唯一的 也就是说 对于每个ID X1不
  • JSONObject.append 到对象中 - 结果是嵌套数组?

    以下代码生成一个嵌套数组作为包含三个项目的键的结果 import org codehaus jettison json JSONObject JSONObject ret new JSONObject for Key key keys re
  • 类和私有变量

    class Test1 def init self self test 1 def getvalue self return self test class Test2 Test1 def init self Test1 init self
  • 有没有办法检测是否按下了某个键?

    我正在 Windows 计算机上的 cygwin 中编译并执行我的程序 我对 C 非常缺乏经验 但我想要一种方法来检测是否按下了某个键而不提示用户 例如我 我的具有所需功能的伪代码如下所示 char ch while 1 if KeyBee
  • 带身份验证的 Laravel api 路由

    我正在尝试创建一个 api 路由 只有发出请求的用户登录后才能访问 这就是我的routes api php但它返回 error Unauthenticated Route group middleware gt auth api funct
  • x86-64 (AMD64) 架构中是否有默认操作数大小?

    这是关于 x86 64 AMD64 架构中操作数大小覆盖前缀的问题 这是一堆汇编指令 nasm 及其编码 经过new我的意思是 r8 r15 寄存器 67 address size override prefix 4x operand si