【问题标题】:Error: Operation size not specified - NASm错误:未指定操作大小 - NASm
【发布时间】:2016-11-12 20:26:53
【问题描述】:

我正在使用 16 位 NASM 程序集,遇到无法构建代码的问题。该错误发生在此处的所有 MOV 行上:

  section .bss
  x_coord   RESB 8 ; [x_coord] is the head, [x_coord+2] is the next cell, etc.
  y_coord   RESB 8 ; Same here
  pixel_x  RESB 2  ; Storage for calculations
  pixel_y  RESB 2  ; Storage for calculations

   ...


  MOV [pixel_x], [x_coord]
  MOV [pixel_y], [y_coord]
  CALL DrawPixel

  MOV [pixel_x], [x_coord+2]
  MOV [pixel_y], [y_coord+2]
  CALL DrawPixel

  MOV [pixel_x], [x_coord+4]
  MOV [pixel_y], [y_coord+4]
  CALL DrawPixel

  MOV [pixel_x], [x_coord+6]
  MOV [pixel_y], [y_coord+6]
  CALL DrawPixel

我听说这是因为汇编器不知道变量的大小。我尝试了一些在线帖子建议的MOV [pixel_x], byte [x_coord],但这给出了同样的错误。我只想将 x_coord 和 y_coord 的前两个字节复制到 pixel_x/pixel_y 中,然后是接下来的两个,然后是接下来的两个,然后是接下来的两个。我怎样才能做到这一点?

谢谢:)

【问题讨论】:

    标签: assembly nasm x86-16 mov


    【解决方案1】:

    处理器没有简单的内存到内存移动指令,所以如果你想一次移动两个字节,正确的做法是使用寄存器作为中介:

    MOV ax, word [x_coord]
    MOV word [pixel_x], ax
    MOV ax, word [y_coord]
    MOV word [pixel_y], ax
    CALL DrawPixel
    

    由于您的变量在内存中是连续的,您也可以这样做:

    MOV eax, dword [x_coord]  ; move BOTH x_coord AND y_coord into the register
    MOV dword [pixel_x], eax  ; populates BOTH pixel_x AND pixel_y
    CALL DrawPixel
    

    如果你只绘制四个像素,你可以一个接一个地调用:

    MOV eax, dword [x_coord]
    MOV dword [pixel_x], eax
    CALL DrawPixel
    MOV eax, dword [x_coord+2]
    MOV dword [pixel_x], eax
    CALL DrawPixel
    MOV eax, dword [x_coord+4]
    MOV dword [pixel_x], eax
    CALL DrawPixel
    MOV eax, dword [x_coord+6]
    MOV dword [pixel_x], eax
    CALL DrawPixel
    

    如果要绘制更多像素,可以考虑编写循环。

    (另外:还可以考虑实现DrawPixel 以使用来自寄存器的值。)

    【讨论】:

    • 这看起来很完美,谢谢!关于您的上一条评论,我使用了内存,因为我不能 100% 确定我可以安全地将哪些寄存器用于这样的临时值。哪个最适合这个?
    • @Nathan:这取决于函数的 ABI。如果您编写了这两个函数,则可以制定自己的调用约定。查看x86 tag wiki 中的一些现有 ABI / 调用约定。 Microsoft 的 32 位 __vectorcall 可能是 16 位代码的一个很好的起点,其中前两个整数参数在寄存器中传递。 (edx 和 ecx,IIRC)。 32 位 SysV (Linux) 专门在堆栈上传递参数。即使这样也比在全局变量中传递 args 更好。 (push 使用内存操作数)。
    • @Nathan:如果您在 64 位模式下使用 nasm,则整数值参数按以下顺序传递:rdirsirdxrcx、@987654333 @, r9,所以你很可能通过将你的两个坐标打包到rdi 的低 32 位中来编写你的 drawPixel 函数,即edi。在函数内,应保留rbprbxr12r13r14r15。但是函数调用约定还有很多(包括对齐、浮点寄存器、返回值等),请参阅nasm.us/doc/nasmdo11.htmlx86-64.org/documentation/abi.pdf
    • movs 指令?
    • movs 非常适合移动大块内存,但 OP 正在谈论将 32 位从一个内存位置移动到另一个内存位置,所以我肯定会避免使用 movs。我在回答中确实提到没有 simple 内存到内存移动指令。我不认为movs 是“简单的”,因为隐式使用了索引寄存器。 :-)
    猜你喜欢
    • 2021-03-02
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2014-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多