3 ms·
Read https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Prefixes https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Pr... The REP prefixes are th
by db48x 3y ago
Read https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Prefixes https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Pr...
The REP prefixes are the most common; they just let you perform the same instruction a variable number of times. It looks in the CX register for the count. This makes many common loops really, really short, especially for moving objects around in memory. The memcpy function is often inlined as a single REP MOVS instruction, possibly with an instruction to copy the count into CX if it isn’t already there.
I suppose the REX (operand size) prefix is pretty common too, since 64–bit programs will want to operate on 64–bit values and addresses pretty frequently.
None of the prefixes toggle things that can be set globally, by the BIOS or otherwise. They all just specify things that the next instruction needs to do.
- pclmulqdq 3y agoThe ModR/M and SIB prefixes are probably the most common prefixes in instructions. They are so common that assemblers elide their existence when you read code. REX is in the same boat: so common that it's usually elided. The VEX prefix is also really common (all of the V* AVX instructions, like VMOVDQ), and then the LOCK prefix (all atomics). After all of those, REP is not that uncommon of a prefix to run into, although many people prefer SIMD memcpy/memset to REP MOVSB/REP STOSB. It is slightly unusual.
- bonzini 3y agoModRM and SIB are not a prefix, they're part of the opcode (second and third byte after all the prefixes and the 0Fh/0F38h/0F3Ah opcode map selectors)
- EarlKing 3y agoMore specifically, they're affixed to certain opcodes that require them. There are a number of byte-sized opcodes that do not require a ModRM or SIB byte (although a number of those got gobbled up to make the REX prefix, but that's another story). TL;DR Weeee! Intel machine language is crazy!
- EarlKing 3y agoThere's a good reason for using vector instructions over REP: Until relatively recently that was how you got maximum performance in small, tight loops. REP is making a comeback precisely because of ERMS and FSRM, so unfortunately this will become a bigger problem going forward.
- epcoa 3y agoThis isn't correct. ModR/M and SIB are not prefixes. They are suffixes and essentially part of the core instruction encoding for certain memory and register access instruction. they are the primary means of encoding the myriad addressing modes of the x86. And their existence is not elided in any meaningful way, their value is explicitly derived from the instruction operands (SIB is scale, index, base), so when you see an instruction like: mov BYTE PTR [rdi+rbx*4],0x4 SIB is determined by the register indices of rdi, rbx, and 4, all right there in the instruction. Likewise, Mod R/M encodes the addressing mode, which is clear from the operands in the assembler listing. Though x86 is such as mess that there are cases where you can encode the same instruction in either a Mod R/M form or a shorter form, eg PUSH/POP. REX is a prefix, but it is a bit special as it must be the last one, and repeats are undefined. It is not elided because of commonality but because its presence and value is usually implied from the operands, it is therefore redundant to list it. For instance, PUSH R12 must use a REX prefix (REX.B with the one byte encoding).
- msm_ 3y agoThis doesn't sound right. REP prefixes are pretty rare. Depending on compiler they are used rarely, for a few specific operations (like rep movsd for memcpy) or usually never. Most common prefixes are by far REX prefixes in 6h4 64bit assembly (don't believe me? Look at the 64bit code in vim and see all those `H` letters around. It's REX.W). Segment override prefixes are another class of prefixes that are used in handwritten assembly (in bootloader or special runtime functions) but almost never used by compilers. In older code, most common prefixes are 0x66h (it doesn't even has opcode, there's no way to emit it directly) and maybe 0x67h. They are all used to modify some aspect of the next executing instruction, for example the "default" register size is 32bit, but you can change it with a prefix. I think an example will help. $ echo 31c0 | xxd -r -ps | ndisasm -b64 /dev/stdin 00000000 31C0 xor eax,eax $ echo 6631c0 | xxd -r -ps | ndisasm -b64 /dev/stdin 00000000 6631C0 xor ax,ax $ echo 4831c0 | xxd -r -ps | ndisasm -b64 /dev/stdin 00000000 4831C0 xor rax,rax And there are also the extensions of base, SIB and Mod/RM fields, mentioned by the article (to the extended set of high registers): $ echo 4431c0 | xxd -r -ps | ndisasm -b64 /dev/stdin 00000000 4431C0 xor eax,r8d $ echo 4131c0 | xxd -r -ps | ndisasm -b64 /dev/stdin 00000000 4131C0 xor r8d,eax