x86_64 无法将 64 位值添加到 rax,“'add' 上的操作数不匹配”
Posted
技术标签:
【中文标题】x86_64 无法将 64 位值添加到 rax,“\'add\' 上的操作数不匹配”【英文标题】:x86_64 Cannot add 64 bit value to rax, "operand mismatch on 'add'"x86_64 无法将 64 位值添加到 rax,“'add' 上的操作数不匹配” 【发布时间】:2019-10-06 15:48:03 【问题描述】:我正在尝试组装一些 64 位代码,但组装失败:
addq $0xffffff7fc0005000, %rax
出现错误:
`add' 的错误操作数类型不匹配
第一个操作数是一个 64 位的值,而后者是一个可以很好地组装的寄存器。该指令前面有一个.code64
伪操作。我正在组装
x86_64-elf-as test.s -o test.o --64
至于汇编器本身,当使用--version
调用时,它会返回:
GNU assembler (GNU Binutils) 2.32
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `x86_64-elf'.
【问题讨论】:
嗯,这是一个令人困惑的错误消息与一个超出范围/不可编码立即数的警告。我称之为可用性错误。他们很容易写出一条错误消息,不会让你去 SO 询问有关它的问题。 我只是好奇。您是否正在编写具有更高半内核的 64 位操作系统? 我问是因为之前您问过一个关于确保某些内容的大小为 0x200 字节的问题。当时我相信您可能一直在编写自定义引导加载程序。在这个问题中,我注意到您使用的是 binutils 的交叉编译器版本。我发现有趣的是 addq$0xffffff7fc0005000
几乎看起来就像有人在最后 2GiB 虚拟地址空间中编写一个更高半的内核时会做的事情。如果这是真的,那么addq $0xffffff7fc0005000
是错误的,可能应该是规范地址$0xffffffffc0005000
addq $0xffffffffc0005000, %rax
不会出错,因为 $0xffffffffc0005000
可以表示为 32 位有符号值 $0xc0005000
,当符号扩展到 64 位时也是 $0xffffffffc0005000
。 (0xc0005000 的第 31 位最高位是值 1,因此当符号扩展时,64 位值中的所有位都取值为 1)。
Can I add 64bit constants to 64bit registers? 是同一问题的 NASM 版本。 (NASM 有更好的错误信息:warning: signed dword immediate exceeds bounds
)
【参考方案1】:
第一个操作数是一个 64 位的值,后一个是一个寄存器,应该可以很好地组装。
不应该,add
的 64 位版本可以采用 8 位或 32 位符号扩展立即数,但不能采用 64 位立即数,这在 x64 中通常很少见。这可以通过查看英特尔软件开发人员手册或其他各种地方来验证,例如this online copy of the ADD lemma。
唯一可以采用完整 64 位立即数(不是 32 位符号扩展)的指令是 mov
。(或 movabs
,因为 GAS 喜欢称此变体,尽管具有较大的数字常量 mov $0x123456789abc, %rcx
will pick the necessary encoding,不要截断数字)。
通常你会 mov
一个 64 位立即数到一个寄存器中,然后使用它。
另一种选择是将值放入内存中,并在带有内存操作数的add
中使用它。
【讨论】:
以上是关于x86_64 无法将 64 位值添加到 rax,“'add' 上的操作数不匹配”的主要内容,如果未能解决你的问题,请参考以下文章