Search code examples
assemblyx86nasmmachine-codeobjdump

Why does `add cx, 1234` in NASM 16 bit mode produce <unknown> with objdump?


I have this:

bits 16
global start
section .text
start:
  add cx, 1234

With this Makefile:

test:
    @nasm -f macho64 test.asm
    @objdump -x86-asm-syntax=intel --full-leading-addr -d test.o
.PHONY: test

It prints:

% make

test.o: file format Mach-O 64-bit x86-64


Disassembly of section __TEXT,__text:

0000000000000000 start:
      0: 81 c1                          <unknown>
      2: d2 04                          <unknown>

Why does it produce the <unknown> and not show the instruction here? Did I do something wrong? Still learning the very basics of machine code so sorry if it's obvious.

It seems to work fine in 32 bit mode:

bits 32
global start
section .text
start:
  add cx, 1234

Outputs:

% make

test.o: file format Mach-O 64-bit x86-64


Disassembly of section __TEXT,__text:

0000000000000000 start:
      0: 66 81 c1 d2 04                 add cx, 1234

Solution

  • opcode 81 in 64-bit mode requires 5 more bytes (modrm + imm32), but your .text segment ends before that so the disassembler gives up. If you pad the text section with some more bytes (like times 10 db 0), you'll get something.

    You used bits 16 to put non-64-bit machine code into a 64-bit object file, so of course you should expect things to be wrong in general.

    16-bit mode has a different default operand-size (16) than 32 and 64-bit mode (32), so the 66 operand-size prefix makes things opposite. Instructions that require a 66 prefix in 32 or 64-bit mode (like add cx, 1234), require it to be absent in 16-bit mode. (As mentioned in @fuz's answer to your previous question)