x86 asm: move string instructions from x86-assembly-cheat

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-06-19 00:00:00 +00:00
parent e42d770e74
commit 6a9299599e
8 changed files with 312 additions and 43 deletions

View File

@@ -12311,6 +12311,17 @@ When reading disassembly, many instructions have either a `.n` or `.w` suffix.
Bibliography: https://stackoverflow.com/questions/27147043/n-suffix-to-branch-instruction
=== NOP instructions
* x86: link:userland/arch/x86_64/nop.S[NOP]
* ARM: <<arm-nop-instruction>>
No OPeration.
Does nothing except take up one processor cycle and occupy some instruction memory.
Applications: http://stackoverflow.com/questions/234906/whats-the-purpose-of-the-nop-opcode
== x86 userland assembly
Arch agnostic infrastructure getting started at: <<userland-assembly>>.
@@ -12354,29 +12365,29 @@ Bibliography:
<<intel-manual-1>> 5.1.2 "Binary Arithmetic Instructions":
* link:userland/arch/x86_64/add.S[ADD]
** link:userland/arch/x86_64/inc.S[INC]
** link:userland/arch/x86_64/adc.S[ADC]
* link:userland/arch/x86_64/sub.S[SUB]
** link:userland/arch/x86_64/dec.S[DEC]
** link:userland/arch/x86_64/sbb.S[SBB]
* link:userland/arch/x86_64/mul.S[MUL]
** link:userland/arch/x86_64/neg.S[NEG]
** link:userland/arch/x86_64/imul.S[IMUL]
* link:userland/arch/x86_64/div.S[DIV]
** link:userland/arch/x86_64/div_overflow.S[DIV overflow]
** link:userland/arch/x86_64/div_zero.S[DIV zero]
** link:userland/arch/x86_64/idiv.S[IDIV]
* link:userland/arch/x86_64/cmp.S[CMP]
* link:userland/arch/x86_64/add.S[]: ADD
** link:userland/arch/x86_64/inc.S[]: INC
** link:userland/arch/x86_64/adc.S[]: ADC
* link:userland/arch/x86_64/sub.S[]: SUB
** link:userland/arch/x86_64/dec.S[]: DEC
** link:userland/arch/x86_64/sbb.S[]: SBB
* link:userland/arch/x86_64/mul.S[]: MUL
** link:userland/arch/x86_64/neg.S[]: NEG
** link:userland/arch/x86_64/imul.S[]: IMUL
* link:userland/arch/x86_64/div.S[]: DIV
** link:userland/arch/x86_64/div_overflow.S[]: DIV overflow
** link:userland/arch/x86_64/div_zero.S[]: DIV zero
** link:userland/arch/x86_64/idiv.S[]: IDIV
* link:userland/arch/x86_64/cmp.S[]: CMP
=== x86 logical instructions
<<intel-manual-1>> 5.1.4 "Logical Instructions"
* link:userland/arch/x86_64/and.S[AND]
* link:userland/arch/x86_64/not.S[NOT]
* link:userland/arch/x86_64/or.S[OR]
* link:userland/arch/x86_64/xor.S[XOR]
* link:userland/arch/x86_64/and.S[]: AND
* link:userland/arch/x86_64/not.S[]: NOT
* link:userland/arch/x86_64/or.S[]: OR
* link:userland/arch/x86_64/xor.S[]: XOR
=== x86 shift and rotate instructions
@@ -12400,10 +12411,10 @@ Keeps the same sign on right shift.
Not directly exposed in C, for which signed shift is undetermined behavior, but does exist in Java via the `>>>` operator. C compilers can omit it however.
+
SHL and SAL are exactly the same and have the same encoding: https://stackoverflow.com/questions/8373415/difference-between-shl-and-sal-in-80x86/56621271#56621271
* link:userland/arch/x86_64/rol.S[ROL and ROR]
* link:userland/arch/x86_64/rol.S[]: ROL and ROR
+
Rotates the bit that is going out around to the other side.
* link:userland/arch/x86_64/rol.S[RCL and RCR]
* link:userland/arch/x86_64/rol.S[]: RCL and RCR
+
Like ROL and ROR, but insert the carry bit instead, which effectively generates a rotation of 8 + 1 bits. TODO application.
@@ -12411,26 +12422,28 @@ Like ROL and ROR, but insert the carry bit instead, which effectively generates
<<intel-manual-1>> 5.1.6 "Bit and Byte Instructions"
* link:userland/arch/x86_64/bt.S[BT]
* link:userland/arch/x86_64/bt.S[]: BT
+
Bit test: test if the Nth bit a bit of a register is set and store the result in the CF FLAG.
+
....
CF = reg[N]
....
* link:userland/arch/x86_64/btr.S[BTR]
* link:userland/arch/x86_64/btr.S[]: BTR
+
Do a BT and then set the bit to 0.
* link:userland/arch/x86_64/btc.S[BTC]
* link:userland/arch/x86_64/btc.S[]: BTC
+
Do a BT and then swap the value of the tested bit.
* link:userland/arch/x86_64/setcc.S[SETcc]
* link:userland/arch/x86_64/setcc.S[]: SETcc
+
Set a a byte of a register to 0 or 1 depending on the cc condition.
* link:userland/arch/x86_64/popcnt.S[POPCNT]
Set a byte of a register to 0 or 1 depending on the cc condition.
+
Bibliography: https://stackoverflow.com/questions/1406783/how-to-read-and-write-x86-flags-registers-directly/30952577#30952577
* link:userland/arch/x86_64/popcnt.S[]: POPCNT
+
Count the number of 1 bits.
* link:userland/arch/x86_64/test.S[TEST]
* link:userland/arch/x86_64/test.S[]: TEST
+
Like <<x86-binary-arithmetic-instructions,CMP>> but does AND instead of SUB:
+
@@ -12442,12 +12455,12 @@ ZF = (!(X && Y)) ? 1 : 0
<<intel-manual-1>> 5.1.7 "Control Transfer Instructions"
* link:userland/arch/x86_64/jmp.S[JMP]
** link:userland/arch/x86_64/jmp_indirect.S[JMP indirect]
* link:userland/arch/x86_64/jmp.S[]: JMP
** link:userland/arch/x86_64/jmp_indirect.S[]: JMP indirect
==== x86 Jcc instructions
link:userland/arch/x86_64/jcc.S[Jcc]
link:userland/arch/x86_64/jcc.S[]
Jump if certain conditions of the flags register are met.
@@ -12472,29 +12485,61 @@ JG vs JA and JL vs JB:
==== x86 LOOP instruction
link:userland/arch/x86_64/loop.S[LOOP]
link:userland/arch/x86_64/loop.S[]
Vs <<x86-jcc-instructions,Jcc>>: https://stackoverflow.com/questions/6805692/x86-assembly-programming-loops-with-ecx-and-loop-instruction-versus-jmp-jcond Holy CISC!
==== x86 string instructions
<<intel-manual-1>> 5.1.8 "String Instructions"
These instructions do some operation on an array item, and automatically update the index to the next item:
* First example explained in more detail
** link:userland/arch/x86_64/stos.S[]: STOS: STOre String: store register to memory. STOSD is called STOSL in GNU GAS as usual: https://stackoverflow.com/questions/6211629/gcc-inline-assembly-error-no-such-instruction-stosd
* Further examples
** link:userland/arch/x86_64/cmps.S[]: CMPS: CoMPare Strings: compare two values in memory with addresses given by RSI and RDI. Could be used to implement `memcmp`. Store the result in JZ as usual.
** link:userland/arch/x86_64/lods.S[]: LODS: LOaD String: load from memory to register.
** link:userland/arch/x86_64/movs.S[]: MOVS: MOV String: move from one memory to another with addresses given by RSI and RDI. Could be used to implement `memmov`.
** link:userland/arch/x86_64/scas.S[]: SCAS: SCan String: compare memory to the value in a register. Could be used to implement `strchr`.
The RSI and RDI registers are actually named after these intructions! S is the source of string instructions, D is the destination of string instructions.
The direction of the index increment depends on the direction flag of the FLAGS register: 0 means forward and 1 means backward: https://stackoverflow.com/questions/9636691/what-are-cld-and-std-for-in-x86-assembly-language-what-does-df-do
These instructions were originally developed to speed up "string" operations such as those present in the `<string.h>` header of the C standard library.
However, as computer architecture evolved, those instructions might not offer considerable speedups anymore, and modern glibc such as 2.29 just uses <<x86-simd>> operations instead:, see also: https://stackoverflow.com/questions/33480999/how-can-the-rep-stosb-instruction-execute-faster-than-the-equivalent-loop
===== x86 REP prefix
Example: link:userland/arch/x86_64/rep.S[]
Repeat a string instruction RCX times:
As the repetitions happen:
* RCX decreases, until it reaches 0
* RDI and RSI increase
The variants: REPZ, REPNZ (alias REPE, REPNE) repeat a given instruction until something happens.
REP and REPZ also additionally stop if the comparison operation they repeat fails.
* REP: INS, OUTS, MOVS, LODS, and STOS
* REPZ: CMPS and SCAS
=== x86 miscellaneous instructions
<<intel-manual-1>> 5.1.13 "Miscellaneous Instructions"
==== x86 NOP instruction
link:userland/arch/x86_64/nop.S[NOP]
No OPeration.
Does nothing except take up one processor cycle and occupy some instruction memory.
Applications: http://stackoverflow.com/questions/234906/whats-the-purpose-of-the-nop-opcode
NOP: <<nop-instructions>>
=== x86 random number generator instructions
<<intel-manual-1>> 5.1.15 Random Number Generator Instructions
Example: link:userland/arch/x86_64/rdrand.S[RDRAND]
Example: link:userland/arch/x86_64/rdrand.S[]: RDRAND
If you run that executable multiple times, it prints a random number every time to stdout.
@@ -12508,7 +12553,7 @@ RDRAND sets the carry flag when data is ready so we must loop if the carry flag
==== x86 CPUID instruction
Example: link:userland/arch/x86_64/cpuid.S[CPUID]
Example: link:userland/arch/x86_64/cpuid.S[]
Fills EAX, EBX, ECX and EDX with CPU information.
@@ -13299,6 +13344,8 @@ See: <<arm-adr-instruction>>.
==== ARM NOP instruction
Parent section: <<nop-instructions>>
There are a few different ways to encode NOP, notably MOV a register into itself, and a dedicated miscellaneous instruction.
Example: link:userland/arch/arm/nop.S[]