x86_64 汇编器的 gcc 错误(操作码 0x83 cmp m64/imm8)

Posted

技术标签:

【中文标题】x86_64 汇编器的 gcc 错误(操作码 0x83 cmp m64/imm8)【英文标题】:gcc error for x86_64 assembler (opcode 0x83 cmp m64/imm8) 【发布时间】:2020-06-14 06:04:25 【问题描述】:

当我尝试编译时

int main(void)

        __asm__("cmp  $0x1,0x555557e20b58");    

    return 0;

我明白了

main.cpp: Assembler messages:
main.cpp:6: Error: operand type mismatch for `cmp'

编译命令是“gcc main.cpp -o main”。它适用于 m32 值,例如"asm("cmp $0x1,0x555557e2");".

根据this X86 Opcode and Instruction Reference,有一个操作码为0x83的命令,modrm_reg:7,称为“CMP”,第一个参数:r/m16/32/64,第二个参数:imm8,描述:“比较两个操作数”。为什么 gcc 找不到呢?我尝试使用 CMPQ,但无济于事。

我尝试编译这条指令的原因是我想查看机器代码。

这来自“英特尔® 64 和 IA-32 架构软件开发人员手册”:

REX.W + 83 /7 ib    CMP r/m64, imm8 MI  Valid   N.E.    Compare imm8 with r/m64.

所以对于机器代码,我希望

第一个字节为 0x48 (REX.W) 和 第二个字节为操作码 0x83。 对于第 3 个字节 (ModR/M),我迷路了:

手册上说“/digit - 0 到 7 之间的数字表示指令的 ModR/M 字节仅使用 r/m(寄存器或内存)操作数。reg 字段包含提供扩展的数字指令的操作码。”因此,据此,我理解 modrm_reg = 7。但是 r/m 的含义是什么?

字节 4 - 11 将是 8 字节值 字节 12 比较 imm8 值

【问题讨论】:

x86指令只有1个立即数,只有movabs可以接收64位立即数,其他最多32位立即数 @phuclv,问题不在于直接,而在于寻址模式。 您还需要一个操作数大小后缀,因为cmp $1, addr 无法推断您是否要比较字节、字等。如果您想要r/m64 形式,则使用cmpq 【参考方案1】:

x86_64 中没有指定 64 位绝对地址的指令格式——在 32 位模式下指定 32 位绝对地址的 r/m 编码用于 RIP 相对寻址——一个 32-指令指针的位(有符号)位移。

所以如果你想在 64 位模式下做这样的事情,你需要类似的东西

 __asm__("cmp  $0x1,symbol(%rip)");

并在链接器中安排将代码链接到固定地址(无 ASLR),并将 symbol 定义为 0x555557e20b58。

【讨论】:

如果他真的想访问一个绝对地址,最好将它加载到一个寄存器中并取消引用它,而不是使用 rip-relative 寻址。 有一组移动指令允许使用 64 位地址:将内存移入/移出 al/ax/eax/rax。 请注意,x86_64 中有绝对寻址模式,但也只需要 32 位位移。

以上是关于x86_64 汇编器的 gcc 错误(操作码 0x83 cmp m64/imm8)的主要内容,如果未能解决你的问题,请参考以下文章

Ubuntu 16.04下使用gcc输出汇编的.0文件为可执行文件时出现:`_start'被多次定义

x86_64 - 操作码映射。可能的错误?

x86_64 ABI:反汇编问题

使用 GNU 汇编器在 x86_64 中调用 printf

动手开发操作系统- 0x1

“错误:命令'x86_64-linux-gnu-gcc'失败,退出状态为1”在virtualenv中