8

Why in x64 some of the opcodes are invalid (06, 07 for example), whereas in x86 are used for fairly basic instructions (06 and 07 being push and pop)? I thought that those simplest instructions would do nicely in both architectures.

Why they disabled some of those simple instructions in x64? Why wouldn't they work? Why they disabled some opcodes, creating holes in opcode list, when they could instead assign them to x64 versions of instructions?

Reference:

http://ref.x86asm.net/coder32.html

http://ref.x86asm.net/coder64.html

Błażej Michalik
  • 4,474
  • 40
  • 55
  • 2
    Push/popping segment registers just doesn't make any sense in x64 mode. – Hans Passant Jun 19 '15 at 12:48
  • Related: [x86 32 bit opcodes that differ in x86-x64 or entirely removed](https://stackoverflow.com/q/32868293) lists most of them, and some opcodes that were repurposed instead of faulting. (Like one-byte inc/dec becoming REX prefixes, and `arpl` becoming `movsxd`.) – Peter Cordes Dec 11 '21 at 19:05

2 Answers2

10

The 06 and 07 opcodes in 32-bit mode are the instructions PUSH ES and POP ES. In 64-bit mode, the segment registers CS, DS, ES, and SS are no longer used to determine memory addresses: the processor assumes a base address of 0 and no size limits. As there's now usually no reason for applications (other than the operating system itself) to access these registers, the push/pop opcodes for changing and accessing them were removed, leaving only mov to/from Sreg (which is just 2 total opcodes; the register number goes in the ModRM byte instead of part of the 1-byte opcode). That's totally sufficient for something that's almost never needed.

The FS and GS segment registers can still set the base address in 64-bit mode, so push and pop opcodes related to them have not been removed. (These 2-byte 0F xx opcodes were added in 386, and are a less valuable part of opcode space than the old 1-byte opcodes for 8086 segment registers).

Push/pop or mov of segment registers is not how OSes would typically set FS or GS segment bases, though: that would require a GDT or LDT entry, and could only set a base within the low 32 bits. 64-bit OSes would use the associated MSRs to read and write the bases directly, not the architectural registers. (Modern 32-bit OSes do that, too, unless running on old hardware that doesn't support the segment base MSRs.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
interjay
  • 107,303
  • 21
  • 270
  • 254
  • CS is still used actually. – harold Jun 19 '15 at 16:06
  • 2
    @harold You're right, it's still used to set attributes for the code segment (such as enabling 64-bit mode), but no longer used to determine memory addresses. – interjay Jun 19 '15 at 16:59
  • @interjay: I made some significant edits; your answer seemed to imply that push/pop were the only way to access those regs, not mentioning `mov`. Also implying that FS or GS base are set via `pop`, not `wrmsr`. Even if the seg regs could still be used, OSes would likely still use a flat memory model so it would still have been a sensible design to remove the push/pop for those regs and leave only `mov`. – Peter Cordes Dec 19 '20 at 05:58
4

For all CPUs there's something like an "opcode space". For example, if a CPU used 8-bit opcodes then there'd be a max. of 256 instructions it could have. The larger opcodes are the more opcodes you can have, but the harder it is to fetch and decode them quickly.

80x86 is a relatively old architecture. It started out with a modest opcode space consisting of mostly 1-byte and 2-byte opcodes. Each time CPU manufacturers add a new feature it takes more opcodes from the opcode space. They ran out of opcodes. They ran out quickly.

To work around it they started doing things like adding escape codes and prefixes to artificially extended the opcode space. For an example, for recent AVX instructions you're looking at a VEX prefix followed by an old/recycled escape code (e.g. 0xF0), followed by an old/recycled address/operand size prefix (e.g. 0x66), followed by another 4 bytes. It's not pretty.

At the same time there's old instructions that are rarely used now (AAD, AAM, etc) and instructions with multiple/redundant opcodes (INC/DEC) that were consuming valuable "1-byte" opcodes. These couldn't/can't be removed entirely due to backward compatibility.

However; when 64-bit was being designed there simply wasn't any 64-bit code to be compatible with - backward compatibility didn't matter. The 1-byte opcodes being consumed by "not very important" instructions could be recycled; making those instructions invalid in 64-bit code (but freeing up some of the valuable 1-byte opcodes).

Most of those 1-byte opcodes (the entire 1-byte INC/DEC group if I remember right) got recycled immediately for the REX prefix that was needed to support 64-bit operands. Some weren't and became "free for future extensions" (with the restriction that the extension can only work in 64-bit code because those instructions are still valid in 16-bit and 32-bit code).

Brendan
  • 35,656
  • 2
  • 39
  • 66
  • There are other instructions that could have been removed for AMD64 mode. They could even have completely redesigned the binary encoding. I assume the reason for *not* making many changes was so the same silicon could decode 32 and 64bit mode, without much conditional logic that depended on what mode the CPU was in. – Peter Cordes Jul 13 '15 at 05:52
  • @PeterCordes: Yes. Note that at the time when 64-bit 80x86 was introduced, Intel was trying to push everyone that needed 64-bit to an alternative (Itanium); and if Itanium succeeded AMD would have been dead (no cross-licensing agreement for Itanium). By making 64-bit mostly the same as existing 32-bit they reduced the time it took to release CPUs and the time it took other people (compilers, operating systems) to support it; and prevented a "too late to market" disaster. It was the right decision at the time (but rising competition from 64-bit ARM has made it "unfortunate for long-term"). – Brendan Dec 19 '20 at 03:56