Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
769 views
in Technique[技术] by (71.8m points)

assembly - x86 XOR opcode differences

looking at http://ref.x86asm.net/coder32.html I found two opcodes that match for the statement

xor eax,eax

1) opcode 31 XOR r/m16/32 r16/32

2) opcode 33 XOR r16/32 r/m16/32

both refers to 32bit register for operand1 and operand2. So, is there any differences in this specific case of the XORing two 32bit registers ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

x86 has 2 redundant ways to encode a 2-register instance of any of the basic ALU instructions (that date back to 8086), using either the r/m source and r/m destination forms.

This redundancy for reg,reg encoding is a consequence of how x86 machine code allows a memory-destination or a memory-source for most instructions: instead of spending bits in the ModR/M byte to have a flexible encoding for both operands, there are simply two separate opcodes for most instructions.

(This is why two explicit memory operands, like xor [eax], [ecx], isn't allowed for any instruction. Only a few instructions where one or both memory operands are implicit, like rep movs or push [mem] allow two memory operands, never one instruction with two separate ModR/M-encoded addressing modes.)


There are patterns to the encodings

Notice that 31 vs. 33 for word/dword/qword-sized xor differ only in bit #1. Other instructions like 29 vs. 2B sub follow the same pattern. Bit #1 is sometimes called the "direction" bit of the opcode. (Not to be confused with DF in EFLAGS, the direction flag).

Also note that byte vs. word/dword/qword operand-size versions of those instructions differ only in the low bit, like 30 XOR r/m8, r8 vs. 31 XOR r/m16, r16. Again, this pattern shows up in the ALU instruction encodings that date back to 8086. Bit #0 of those opcodes is sometimes called the "size" bit.

These "basic ALU" instructions that have an encoding for each direction and size combo date back to original 8086; many later instructions like 386 bsf r, r/m or 186 imul r, r/m, imm don't have a form that could allow a memory destination. Or for bt* r/m, r only the destination can be reg/mem.

That's also why later instructions (or new forms of them like imul) usually don't have a separate opcode for byte operand-size, only allowing word/dword/qword via the normal prefix mechanisms. 8086 used up much of the coding space, and later extensions wanted to leave room for more future extensions. So that's why there's no imul r, r/m8.

(dword and qword operand size were themselves extensions; 8086 didn't have operand-size or REX prefixes. So original 8086 was fairly sensible in terms of using its opcode coding space, and having patterns to make decoding not a total mess.)


No execution differences between forms

For reg,reg instructions, there's no difference in how they decode and execute on any CPUs I'm aware of; the only time you need to care about which encoding your assembler uses is when you want the machine code to meet some other requirement, like using only bytes that represent printable ASCII characters. (e.g. for an exploit payload).


Specifying which form you want the assembler to use

Some assemblers have syntax for overriding their default choice of encoding, e.g. GAS had a .s suffix to get the non-default encoding. That's now deprecated, and you should use {load} or {store} prefixes before the mnemonic (see the docs), like so:

{load} xor %eax, %ecx
{store} xor %eax, %ecx
{vex3} vpaddd %xmm0, %xmm1, %xmm1
vpaddd %xmm0, %xmm1, %xmm1        # default is to use 2-byte VEX when possible

gcc -c foo.S && objdump -drwC foo.o

0:   31 c1                   xor    %eax,%ecx
2:   33 c8                   xor    %eax,%ecx
4:   c4 e1 71 fe c8          vpaddd %xmm0,%xmm1,%xmm1
9:   c5 f1 fe c8             vpaddd %xmm0,%xmm1,%xmm1

(Related: What methods can be used to efficiently extend instruction length on modern x86? for use-cases for {vex3}, {evex} and {disp32}.)

NASM also has {vex2}, {vex3}, and {evex} prefixes with the same syntax as GAS, e.g. {vex3} vpaddd xmm1, xmm1, xmm0. But I don't see a way to override the op r/m, r vs. op r, r/m choice of opcodes.


Related Q&As, some basically duplicates


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...