title: Why do 32-bit immediates with IMUL give warnings in NASM and errors in GCC?
body: <p>I am currently investigating some strange behaviour with the <code>imul</code> instruction, because the official Intel manual seems to differ slightly from reality.</p>
  <p>The first thing I noticed is that the Intel manual does not consider this example to be a correct instruction:</p>
  <pre class="lang-none prettyprint-override"><code>imul rax, 2
  </code></pre>
  <p>yet both GCC/GAS (with <code>.intel_syntax noprefix</code>) and NASM accept this instruction without problem. Using <code>objdump -d</code> showed me this:</p>
  <pre class="lang-none prettyprint-override"><code>48 6b c0 02             imul   $0x2,%rax,%rax
  </code></pre>
  <p>meaning it gets translated into a different instruction that is in fact documented in the manual.</p>
  <p>I already find this weird and would like to know, why this even exists. The only place I could find this documented was in the <a href="https://nasm.us/xdoc/2.15rc9/html/nasmdocb.html" rel="nofollow noreferrer">NASM instruction set</a> and, weirdly enough, in the Description of the <code>imul</code> instruction in the Intel manual. The latter reads:</p>
  <blockquote>
  <ul>
  <li><strong>Two-operand form</strong> — With this form the destination operand (the first operand) is multiplied by the source operand (second operand). The destination operand is a general purpose register and <strong><em>the source operand is an immediate value</em></strong>, a general-purpose register, or a memory location. The intermediate product (twice the size of the input operand) is truncated and stored in the destination operand location.</li>
  </ul>
  </blockquote>
  <p>That is inconsistent with the Opcode table of that same instruction.</p>
  <p>The NASM instruction set also mentions <code>imul reg64, sbytedword</code> and <code>imul reg64, imm</code> instructions, neither of which I understand what they mean. <code>imm</code> would imply that 64-bit immediates could be used as well, would it not? And the meaning of <code>sbytedword</code> is unclear to me.</p>
  <p>Now to the 32-bit immediates: The NASM instruction set mentions <code>imul reg64, imm32</code> while both the Intel manual and the NASM set mention <code>imul r64, r/m64, imm32</code>. However, normally when an immediate of a lower bitcount than the destination operand is used, the Intel manual specifically mentions sign-extension in the description column of the Opcode table. In this case, it is not mentioned, so I wondered what would happen if I happened to use a negative 32-bit immediate (in other words, requiring all 32 bits).</p>
  <p>This is the assembly code I tested this with:</p>
  <pre class="lang-none prettyprint-override"><code>        global  imm_test
  
          section .text
  
  imm_test:
          mov     rax, rdi
          imul    rax, 0xFFDFFFFF
          ret
  </code></pre>
  <p>Then I called the <em>imm_test</em> function from C:</p>
  <pre class="lang-c prettyprint-override"><code>#include &lt;stdio.h&gt;
  
  int imm_test(int n);
  
  int main() {
      printf(&quot;%d\n&quot;, imm_test(1));
      return 0;
  }
  </code></pre>
  <p>If that 32-bit immediate were to be sign-extended, the value I would assume would have to be printed is <code>-2097153</code>, which, when using NASM to assemble and GCC to compile and link, is exactly what is printed.<br />
  And yet NASM gives me this warning:</p>
  <blockquote>
  <pre class="lang-none prettyprint-override"><code>test.asm:7: warning: signed dword immediate exceeds bounds [-w+number-overflow]
  test.asm:7: warning: dword data exceeds bounds [-w+number-overflow]
  </code></pre>
  </blockquote>
  <p>However, looking at the disassembly again, the instruction is encoded exactly the way I would expect it to be:</p>
  <pre class="lang-none prettyprint-override"><code>48 69 c0 ff ff df ff    imul   $0xffffffffffdfffff,%rax,%rax
  </code></pre>
  <p>It's a 32-bit immediate sign-extended to 64-bit.</p>
  <p>When I change the syntax of the assembly code to GAS's <code>.intel_syntax noprefix</code> like so:</p>
  <pre class="lang-none prettyprint-override"><code>        .intel_syntax noprefix
          .global  imm_test
  
          .text
  
  imm_test:
          mov     rax, rdi
          imul    rax, 0xFFDFFFFF
          ret
  </code></pre>
  <p>and try to assemble this with the GNU assembler, I don't just get a warning, I get an error:</p>
  <blockquote>
  <pre class="lang-none prettyprint-override"><code>test.S: Assembler messages:
  test.S:8: Error: operand type mismatch for `imul
  </code></pre>
  </blockquote>
  <p>Changing the <code>imul</code> instructions to the properly documented <code>imul rax, rax, 0xFFDFFFFF</code> version does not change anything.</p>
  <p>So I'm wondering, why is the documentation for <code>imul</code> so inconsistent, and why are 32-bit immediates officially supported (and also work correctly), yet they give errors or warnings?</p>