To understand what the .s
suffix means, you need to understand how x86 instructions are encoded. If we take adc
as an example, there are four main forms that the operands can take:
- The source operand is an immediate, and the destination operand is the accumulator register.
- The source operand is an immediate, and the destination operand is a register or memory location
- The source operand is a register, and the destination operand is a register or memory location.
- The source operand is a register or memory location, and the destination operand is a register.
And of course there are variants of these for the different operand sizes: 8-bit, 16-bit, 32-bit, etc.
When one of your operands is a register and the other is a memory location, it is obvious which of forms 3 and 4 the assembler should use, but when both operands are registers, either form is applicable. The .s
prefix tells the assembler which form to use (or in the case of a disassembly, shows you which form has been used).
Looking at the specific example of adcb %bl,%dh
, the two ways it can be encoded are as follows:
10 de adcb %bl,%dh
12 f3 adcb.s %bl,%dh
The first byte determines the form of the instruction used, which I'll get back to later. The second byte is what is know as a ModR/M byte and specifies the addressing mode and register operands that are used. The ModR/M byte can be split into three fields: Mod (the most significant 2 bits), REG (the next 3) and R/M (the last 3).
de: Mod=11, REG = 011, R/M = 110
f3: Mod=11, REG = 110, R/M = 011
The Mod and R/M fields together determine the effective address of the memory location if one of the operands is a memory location, but when that operand is just a register, the Mod field is set to 11, and R/M is the value of the register. The REG field obviously just represents the other register.
So in the de
byte, the R/M field holds the dh
register, and the REG fields holds the bl
register. And in the f3
byte, the R/M field holds the bl
register, and the REG fields holds the dh
register. (8-bit registers are encoded as the numbers 0 to 7 in the order al,cl,dl,bl,ah,ch,dh,bh)
Getting back to the first byte, the 10
tells us to use the form 3 encoding, where the source operand is always a register (i.e. it comes from the REG field), and the destination operand is a memory location or register (i.e. it is determined by the Mod and R/M fields). The 12
tells us to use the form 4 encoding, where the operands are the other way around - the source operand is determined by the Mod and R/M fields and the destination operand comes from the REG field.
So the the position the registers are stored in the ModR/M byte are swapped, and the first byte of the instruction tells us which operand is stored where.