Why does AT&T syntax use parens around DX in IN / OUT instructions like inb (%dx),%al

Viewed 121
7c6f:   ec   in     (%dx),%al

Here my doubt is due to ()

Many places I wrote code this worked as take the value inside (%dx) and use it as memory location and value located there is value needed.

But here it should be doing just in %dx,%al ; and %dx hold port no Just like in 0x000,al

2 Answers

in %dx, %al assembles to the same 0xEC byte of machine code, which objdump -d disassembles to in (%dx),%al as you've found.

llvm-objdump -d does use the syntax you expected: inb %dx, %al ; inb $128, %al

AT&T syntax's use of (%dx) for the IO port number in in / out is misleading since it's not a normal addressing mode; DX being the only option. Presumably the designers of AT&T syntax wanted to represent the fact that you're reading or writing I/O address space. But they did a bad job because it's inconsistent with their use of in $0x80, %al for immediate port numbers (as opposed to 0x80 for the port number using the same syntax as an absolute memory address). GAS and LLVM don't even accept in 0x80, %al, so no, not "Just like in 0x000,al".

The in / out instructions access IO space, not memory address space.
The "addresses" in IO space are called port numbers.
IO space is still a thing in modern PCI-express, but most modern devices only have MMIO registers in device memory regions, not IO ports, because IO ports are slower to access.


objdump -drwC -Mintel disassembles to the same syntax Intel uses in their manual entry for the only form of in that has a port in DX and byte operand-size. Note the lack of [dx] brackets.

   0:   ec                      in     al,dx
   1:   e4 80                   in     al,0x80

(%dx) is not one of the valid 16-bit addressing modes, so that specific addressing mode is never valid for any other instruction. But yes, (%reg) such as (%edx) or (%bx) is AT&T addressing-mode syntax for memory operands in instructions which allow a normal reg/mem operand such as mov or add.

See also Why there is no parentheses wrapping around AL register?

Your question is quite unclear, but I'll do my best to answer.

Using (%dx) as the first operand doesn’t work the way you think it does; for in and out,
(%dx) is not a memory operand, unlike how the same syntax is used for operands to other instructions.

The IN instruction takes two operands:

  1. An immediate 8-bit value (like $0x42) or the DX register.

  2. AL, AX, or EAX.

This means you cannot use a memory location for either operand.

Also, as seen in @PeterCordes’s answer, using %dx as a memory address is never valid.

For these two reasons, (%dx) cannot be interpreted as a memory address, so your assembler instead ignores the parentheses and interprets it as the register %dx alone.

That means in (%dx),%al is exactly the same as in %dx,%al.

If you want to take input from a port number stored in memory, you must first load the value into the %dx register:

mov (%something),%dx
in %dx,%al

For more information, consult page 3-494 in Volume 2A of the Intel IA-32 reference manual, or this reference page.

Related