Skip to content

Commit f470d47

Browse files
committed
x86 asm: move most data transfer instructions from x86-assembly-cheat
1 parent fb396be commit f470d47

File tree

7 files changed

+287
-0
lines changed

7 files changed

+287
-0
lines changed

README.adoc

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12361,6 +12361,102 @@ Bibliography:
1236112361
* <<intel-manual-1>> 3.7.5 "Specifying an Offset"
1236212362
* https://sourceware.org/binutils/docs-2.18/as/i386_002dMemory.html
1236312363

12364+
=== x86 data transfer instructions
12365+
12366+
5.1.1 "Data Transfer Instructions"
12367+
12368+
* link:userland/arch/x86_64/lea.S[]: LEA
12369+
* Integer typecasts
12370+
** link:userland/arch/x86_64/movzx.S[]: MOVZX
12371+
** link:userland/arch/x86_64/movsx.S[]: MOVSX
12372+
12373+
==== x86 CQTO and CLTQ instructions
12374+
12375+
Examples:
12376+
12377+
* link:userland/arch/x86_64/cqto.S[] CQTO
12378+
* link:userland/arch/x86_64/cltq.S[] CLTQ
12379+
12380+
Instructions without E suffix: sign extend RAX into RDX:RAX.
12381+
12382+
Instructions E suffix: sign extend withing RAX itself.
12383+
12384+
Common combo with idiv 32-bit, which takes the input from `edx:eax`: so you need to set up `edx` before calling it.
12385+
12386+
Has some Intel vs AT&T name overload hell:
12387+
12388+
* https://stackoverflow.com/questions/17170388/trying-to-understand-the-assembly-instruction-cltd-on-x86/50315201#50315201
12389+
* https://sourceware.org/binutils/docs/as/i386_002dMnemonics.html
12390+
12391+
GNU GAS accepts both syntaxes:
12392+
12393+
[options="header"]
12394+
|===
12395+
|Intel |AT&T |From |To
12396+
12397+
|CBW
12398+
|CBTW
12399+
|AL
12400+
|AX
12401+
12402+
|CWDE
12403+
|CWTL
12404+
|AX
12405+
|EAX
12406+
12407+
|CWD
12408+
|CWTD
12409+
|AX
12410+
|DX:AX
12411+
12412+
|CDQ
12413+
|CLTD
12414+
|EAX
12415+
|EDX:EAX
12416+
12417+
|CDQE
12418+
|CLTQ
12419+
|EAX
12420+
|RAX
12421+
12422+
|CQO
12423+
|CQTO
12424+
|RAX
12425+
|RDX:RAX
12426+
12427+
|===
12428+
12429+
==== x86 CMOVcc instructions
12430+
12431+
* link:userland/arch/x86_64/cmovcc.S[]: CMOVcc
12432+
12433+
mov if a condition is met:
12434+
12435+
....
12436+
CMOVcc a, b
12437+
....
12438+
12439+
Equals:
12440+
12441+
....
12442+
if(flag) a = b
12443+
....
12444+
12445+
where `cc` are the same flags as Jcc.
12446+
12447+
Vs jmp:
12448+
12449+
* http://stackoverflow.com/questions/14131096/why-is-a-conditional-move-not-vulnerable-for-branch-prediction-failure
12450+
* http://stackoverflow.com/questions/27136961/what-is-it-about-cmov-which-improves-cpu-pipeline-performance
12451+
* http://stackoverflow.com/questions/26154488/difference-between-conditional-instructions-cmov-and-jump-instructions
12452+
* http://stackoverflow.com/questions/6754454/speed-difference-between-if-else-and-ternary-operator-in-c?lq=1#comment8007791_6754495
12453+
12454+
Not necessarily faster because of branch prediction.
12455+
12456+
This is partly why the ternary `?` C operator exists: http://stackoverflow.com/questions/3565368/ternary-operator-vs-if-else
12457+
12458+
It is interesting to compare this with ARMv7 conditional executaion: which is available for all instructions: <<arm-conditional-execution>>
12459+
1236412460
=== x86 binary arithmetic instructions
1236512461

1236612462
<<intel-manual-1>> 5.1.2 "Binary Arithmetic Instructions":

userland/arch/x86_64/cltq.S

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-cqto-and-cltq-instructions */
2+
3+
#include <lkmc.h>
4+
5+
LKMC_PROLOGUE
6+
/* CLTQ: top bit is zero: extend with zeroes. */
7+
mov $0x123456787FFFFFFF, %rax
8+
cltq
9+
LKMC_ASSERT_EQ(%rax, $0x000000007FFFFFFF)
10+
11+
/* CLTQ: top bit is one: extend with ones. */
12+
mov $0x1234567880000000, %rax
13+
cltq
14+
LKMC_ASSERT_EQ(%rax, $0xFFFFFFFF80000000)
15+
16+
/* CWTL: zeroes top 32-bits. */
17+
mov $0x123456789ABC8EF0, %rax
18+
cwtl
19+
LKMC_ASSERT_EQ(%rax, $0xFFFF8EF0)
20+
CWTL
21+
22+
/* CBTW. */
23+
mov $0x123456789ABCDE80, %rax
24+
cbtw
25+
LKMC_ASSERT_EQ(%rax, $0x123456789ABCFF80)
26+
CWTL
27+
LKMC_EPILOGUE

userland/arch/x86_64/cmovcc.S

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-cmovcc-instructions */
2+
3+
#include <lkmc.h>
4+
5+
LKMC_PROLOGUE
6+
/* Carry flag clear. */
7+
clc
8+
mov $0, %rax
9+
mov $1, %rbx
10+
/* Don't move: carry flag not set. */
11+
cmovc %rbx, %rax
12+
LKMC_ASSERT_EQ(%rax, $0)
13+
14+
/* Carry flag clear. */
15+
clc
16+
mov $0, %rax
17+
mov $1, %rbx
18+
/* Move because checking NC. */
19+
cmovnc %rbx, %rax
20+
LKMC_ASSERT_EQ(%rax, $1)
21+
22+
/* Carry flag set. */
23+
stc
24+
mov $0, %rax
25+
mov $1, %rbx
26+
/* Move. */
27+
cmovc %rbx, %rax
28+
LKMC_ASSERT_EQ(%rax, $1)
29+
30+
#if 0
31+
/* Immediates not supported:
32+
* Error: operand type mismatch for `cmovc' */
33+
cmovc $1, %rax
34+
#endif
35+
LKMC_EPILOGUE

userland/arch/x86_64/cqto.S

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-cqto-and-cltq-instructions */
2+
3+
#include <lkmc.h>
4+
5+
LKMC_PROLOGUE
6+
/* Quad to Octo: top bit is zero: extend with zeroes. */
7+
mov $0x7FFFFFFFFFFFFFFF, %rax
8+
mov $0x123456789ABCDEF0, %rdx
9+
cqto
10+
mov %rax, %r12
11+
mov %rdx, %r13
12+
/* rax is unchanged. */
13+
LKMC_ASSERT_EQ(%r12, $0x7FFFFFFFFFFFFFFF)
14+
/* rdx is filled with zeros. */
15+
LKMC_ASSERT_EQ(%r13, $0)
16+
17+
/* Quad to Octo: top bit is one: extend with ones. */
18+
mov $0x8000000000000000, %rax
19+
mov $0x123456789ABCDEF0, %rdx
20+
cqto
21+
mov %rax, %r12
22+
mov %rdx, %r13
23+
LKMC_ASSERT_EQ(%r12, $0x8000000000000000)
24+
LKMC_ASSERT_EQ(%r13, $0xFFFFFFFFFFFFFFFF)
25+
26+
/* Intel equivalent syntax also accepte by GNU GAS. */
27+
mov $0x7FFFFFFFFFFFFFFF, %rax
28+
mov $0x123456789ABCDEF0, %rdx
29+
cqo
30+
mov %rax, %r12
31+
mov %rdx, %r13
32+
LKMC_ASSERT_EQ(%r12, $0x7FFFFFFFFFFFFFFF)
33+
LKMC_ASSERT_EQ(%r13, $0)
34+
35+
/* Smaller size example: Double to Quad.
36+
* Also zeroes top 32-bits of RDX like many 32 to 64 operaions. */
37+
mov $0xFFFFFFFF7FFFFFFF, %rax
38+
mov $0x123456789ABCDEF0, %rdx
39+
cltd
40+
mov %rax, %r12
41+
mov %rdx, %r13
42+
LKMC_ASSERT_EQ(%r12, $0xFFFFFFFF7FFFFFFF)
43+
LKMC_ASSERT_EQ(%r13, $0)
44+
45+
/* Even smaller size example: Word to Doubleword.
46+
* Unlike the 32-bit one, does not zero out the top 32-bits of RDX. */
47+
mov $0xFFFFFFFFFFFF7FFF, %rax
48+
mov $0x123456789ABCDEF0, %rdx
49+
cwtd
50+
mov %rax, %r12
51+
mov %rdx, %r13
52+
LKMC_ASSERT_EQ(%r12, $0xFFFFFFFFFFFF7FFF)
53+
LKMC_ASSERT_EQ(%r13, $0x123456789ABC0000)
54+
LKMC_EPILOGUE

userland/arch/x86_64/lea.S

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-data-transfer-instructions
2+
*
3+
* Load Effective Address.
4+
*
5+
* Like MOV, but load the address instead of the value.
6+
*
7+
* Useful in particular for RIP relative addressing.
8+
*/
9+
10+
#include <lkmc.h>
11+
12+
LKMC_PROLOGUE
13+
/* RIP relative addressing. */
14+
lea my_label(%rip), %rax
15+
LKMC_ASSERT_EQ(%rax, $my_label)
16+
17+
/* Also supports the usual addressing operations. */
18+
mov $my_label, %rax
19+
mov $2, %rbx
20+
lea 4(%rax,%rbx,2), %rdx
21+
LKMC_ASSERT_EQ(%rdx, $my_label_2)
22+
LKMC_EPILOGUE
23+
my_label: .skip 8
24+
my_label_2:

userland/arch/x86_64/movsx.S

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-data-transfer-instructions
2+
*
3+
* LIke MOVZX but sign extend.
4+
*/
5+
6+
#include <lkmc.h>
7+
8+
LKMC_PROLOGUE
9+
/* Top bit is 0, extend with zero. */
10+
mov $0x1234567F, %eax
11+
movsx %al, %ax
12+
LKMC_ASSERT_EQ_32(%eax, $0x1234007F)
13+
14+
/* Top bit is 1: extend with one. */
15+
mov $0x12345680, %eax
16+
movsx %al, %ax
17+
LKMC_ASSERT_EQ_32(%eax, $0x1234FF80)
18+
LKMC_EPILOGUE

userland/arch/x86_64/movzx.S

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-data-transfer-instructions
2+
*
3+
* mov and zero extend
4+
*
5+
* unsigned typecast to larger types in 2's complement.
6+
*
7+
* MOV does this automatically from 32 to 64 bits:
8+
* https://stackoverflow.com/questions/11177137/why-do-x86-64-instructions-on-32-bit-registers-zero-the-upper-part-of-the-full-6
9+
*/
10+
11+
#include <lkmc.h>
12+
13+
LKMC_PROLOGUE
14+
/* Top bit is 0, extend with zero. */
15+
mov $0x1234567F, %eax
16+
movzx %al, %ax
17+
LKMC_ASSERT_EQ_32(%eax, $0x1234007F)
18+
19+
/* Top bit is 1: does not matter, stil zero extends. */
20+
mov $0x1234568F, %eax
21+
movzx %al, %ax
22+
LKMC_ASSERT_EQ_32(%eax, $0x1234008F)
23+
24+
#if 0
25+
/* must be a register, otherwise x86 cannot know how to size it:
26+
* Error: unsupported syntax for `movzx' */
27+
movzx $0, %eax
28+
29+
/* Operands have the same size. Fist must be larger.
30+
* Error: unsupported syntax for `movzx' */
31+
movzx %al, %al
32+
#endif
33+
LKMC_EPILOGUE

0 commit comments

Comments
 (0)