yasm movsx,movsxd操作数2的大小无效

时间:2017-11-17 12:22:56

标签: assembly x86 nasm yasm

我正在尝试使用yasm汇编下面的代码。我已经把这里放在了#39;注释yasm报告错误"错误:操作数2"的大小无效。为什么会发生这种错误?

segment .data
    a db 25
    b dw 0xffff
    c dd 3456
    d dq -14

segment .bss
    res resq 1

segment .text
    global _start

_start:
    movsx rax, [a] ; here
    movsx rbx, [b] ; here 
    movsxd rcx, [c] ; here
    mov rdx, [d]
    add rcx, rdx
    add rbx, rcx
    add rax, rbx
    mov [res], rax
    ret

1 个答案:

答案 0 :(得分:2)

对于大多数指令,寄存器操作数的宽度表示内存操作数的宽度,因为两个操作数必须大小相同。例如mov rdx, [d]隐含mov rdx, qword [d],因为您使用的是64位寄存器。

但是相同的movsx / movzx助记符用于字节源和字源操作码,因此除非源是寄存器(如movzx eax, cl),否则它是不明确的。 / p> 具有内存源的

movsx / movzx始终需要明确指定内存操作数的宽度。

movsxd助记符应该暗示32位源大小。 movsxd rcx, [c]与NASM组装,但显然不与YASM合作。 YASM要求您撰写dword,即使它不接受bytewordqword,也不接受movsx rcx, dword [c] (即它需要movsxd助记符用于32位源操作数。)

在NASM中,movsx rcx, dword [c]汇总到movsxd,但movsxd rcx, word [c]仍被拒绝。即在NASM中,普通movsx是完全灵活的,但movsxd仍然是僵硬的。为了人类的利益,我仍然建议使用dword来明确加载宽度。

movsx    rax,  byte [a]
movsx    rbx,  word [b]
movsxd   rcx, dword [c]

请注意,指令的“操作数大小”(由操作数大小前缀确定为16位,或REX.W = 1使其为64位)是{{1的目标宽度} / movsx。不同的源大小使用不同的操作码。

如果不明显,则没有movzx,因为32-bit mov already zero-extends to 64-bit implicitlymovzxd是可编码的,但不推荐(改为使用movsxd eax, ecx。)

在AT& T语法中,不同的源宽度具有不同的助记符,例如movmovsb。目标大小是通常的后缀,因此您可以将movsw写为显式或movsbq (%rsi), %rax以使汇编程序从movsb (%rsi), %rax推断目标大小。

关于源代码的其他内容:

NASM / YASM允许您使用%rax关键字而不是segment,但实际上您提供的是ELF部分名称,而不是可执行部分名称。此外,您可以将只读数据放在section中(作为文本段的一部分链接)。 What's the difference of section and segment in ELF file format

section .rodata你不能ret。它不是一个功能,它是你的ELF切入点。堆栈中的第一件事是_start,而不是有效的返回地址。用它来彻底退出:

argc

请参阅标记wiki,获取更多有用指南的链接(以及底部的调试技巧)。