0

I am having a problem with NASM running on Linux amd64.

Running nasm on a single instruction mov eax, 0x12345678 produces 6 bytes:

00000000 <.data>:
   0:   66 b8 78 56             mov    $0x5678,%ax
   4:   34 12                   xor    $0x12,%al

However, using as on the same instruction in AT&T format mov $0x12345678, %eax produces the correct result with 5 bytes:

0000000000000000 <.text>:
   0:   b8 78 56 34 12          mov    $0x12345678,%eax

What am I missing with NASM?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
iBug
  • 35,554
  • 7
  • 89
  • 134
  • I caught that -- thanks. – David C. Rankin Nov 01 '22 at 01:49
  • 1
    How did you run NASM? Like `nasm foo.asm`, without specifying a 32 or 64-bit object-file format? The default is `nasm -fbin`, where the default is `bits 16`. If I want to see how something assembles, I have an `asm-link` shell script that runs `nasm -felf64 foo.asm` / `objdump -drwC -Mintel foo.o`, so I can run `asm-link -dn foo.asm`. It's included in my answer on [Assembling 32-bit binaries on a 64-bit system (GNU toolchain)](https://stackoverflow.com/q/36861903) – Peter Cordes Nov 01 '22 at 05:39
  • If so, near duplicate of [nasm: error: instruction not supported in 16-bit mode](https://stackoverflow.com/q/54847041), but Brendan's answer here explains the specific symptoms. [Why does \`add cx, 1234\` in NASM 16 bit mode produce with objdump?](https://stackoverflow.com/q/65948483) is more closely related, but explicitly using `bits 16` to put 16-bit machine code into `-f macho64` object file, which is more obviously wrong. [Compiling assembly program to flat-form binary includes extraneous 'f' chars that don't exist in other formats](//stackoverflow.com/q/46478755) is an exact dup – Peter Cordes Nov 01 '22 at 05:47

1 Answers1

3

NASM thinks you're assembling 16-bit code, sees a 32-bit instruction, and slaps a size override prefix on it. Then the disassembler thinks you're disassembling 32-bit code, gets confused by the size override prefix, and assumes it's 2 instructions.

GAS thinks you're assembling 32-bit code, so it doesn't generate a size override prefix.

You can fix NASM by figuring out why it thinks you're assembling 16-bit code. It's the default for the "flat binary" output file format, and if that's the case you can fix it by putting a bits 32 directive somewhere before the 32-bit instruction/s.

Alternatively, maybe you are trying to assemble 16-bit code and GAS is wrong. In that case maybe you need a .code16 directive somewhere before the 16-bit code.

Note that the size override prefix works like a toggle - if the default size is 16 bits then the prefix makes the instruction 32 bit; and if the default size is 32 bits then the same prefix makes the instruction 16 bit.

Brendan
  • 35,656
  • 2
  • 39
  • 66
  • 1
    On AMD64 Linux, GAS knows it's making an x86-64 `.o` if you run it with no options, so it's actually assembling for 64-bit mode. (Where the default operand-size in machine code with no prefixes is also 32-bit, except for a few opcodes, so the overall point is correct.) – Peter Cordes Nov 01 '22 at 05:40