0

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
Lance
  • 75,200
  • 93
  • 289
  • 503

1 Answers1

2

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)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • By 64-bit object file, that's what `nasm -f macho64 test.asm` macho64 is doing, is that what you mean? How do I generate a 16 bit object file then is what I should be doing I guess. I don't there is one of those though, so 32 bit, but I'll still run into the same problem probably. – Lance Jan 29 '21 at 04:20
  • 1
    @LancePollard: Yes, that's what tells `objdump` what mode to assume when disassembling it. `bits 16` / `mov cx, 1234` is *exactly* the same as `db 0x81, 0xc1, 0xd2, 0x04` in terms of the contents of the `.o`, including metadata. An assembler literally just assemblers bytes into the output file at the current position (in the current section, for files other than flat binary) – Peter Cordes Jan 29 '21 at 04:25
  • Excellent, that helps clarify some things, thank you! – Lance Jan 29 '21 at 04:27
  • 2
    @LancePollard: For 16-bit disassembly experiments, probably easiest to make a flat binary: `nasm -fbin test.asm` / `ndisasm -b16 test`. (`-f bin` is actually the default for NASM; you'd use that to make stuff like legacy sectors, or to manually emit the bytes of MachO or ELF metadata for an executable, like in this tutorial: https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html.) Or `objdump` does have options to control what mode to assume for disassembly of a `.o` if you do choose to put code of the wrong bitness in a 32 or 64-bit object file. Or `nasm ... -l/dev/stdout` listing – Peter Cordes Jan 29 '21 at 04:29