diff --git a/README.adoc b/README.adoc index 2ad9cae..c4501c2 100644 --- a/README.adoc +++ b/README.adoc @@ -12136,6 +12136,7 @@ The following <> programs illustrate how to make system calls: * x86_64 ** link:userland/arch/x86_64/freestanding/linux/hello.S[] +** link:userland/arch/x86_64/freestanding/linux/int_system_call.S[] ** link:userland/arch/x86_64/inline_asm/freestanding/linux/hello.c[] ** link:userland/arch/x86_64/inline_asm/freestanding/linux/hello_regvar.c[] * arm @@ -12391,9 +12392,15 @@ For the newer x86_64 registers, the naming convention is somewhat saner: Most of the 8 older x86 general purpose registers are not "really" general purpose in the sense that a few instructions magically use them without an explicit encoding. This is reflected in their names: -* RAX: Accumulator. The general place where you add, subtract and otherwise manipulate results in-place. Magic for example for <> +* RAX: Accumulator. The general place where you add, subtract and otherwise manipulate results in-place. Magic for example for <>. * RCX, RSI, RDI: Counter, Source and Destination. Used in <> +==== x86 FLAGS registers + +https://en.wikipedia.org/wiki/FLAGS_register + +TODO: add some more info here. Just need a link placeholder for now. + === x86 addressing modes Example: link:userland/arch/x86_64/address_modes.S[] @@ -12438,6 +12445,27 @@ Bibliography: ** link:userland/arch/x86_64/movzx.S[]: MOVZX ** link:userland/arch/x86_64/movsx.S[]: MOVSX * link:userland/arch/x86_64/bswap.S[]: BSWAP: convert between little endian and big endian +* link:userland/arch/x86_64/pushf.S[] PUSHF: <> the <> to / from the stack + +==== x86 PUSH and POP instructions + +link:userland/arch/x86_64/push.S[] + +`push %rax` is basically equivalent to: + +.... +sub $8, %rsp +mov %rax, (%rsp) +.... + +and `pop %rax`: + +.... +mov (%rsp), %rax +add $8, %rsp +.... + +Why do those instructions exist at all vs MOV / ADD / SUB: http://stackoverflow.com/questions/4584089/what-is-the-function-of-push-pop-registers-in-x86-assembly/33583134#33583134 ==== x86 CQTO and CLTQ instructions @@ -12450,7 +12478,7 @@ Instructions without E suffix: sign extend RAX into RDX:RAX. Instructions E suffix: sign extend withing RAX itself. -Common combo with idiv 32-bit, which takes the input from `edx:eax`: so you need to set up `edx` before calling it. +Common combo with IDIV 32-bit, which takes the input from EDX:EAX: so you need to set up EDX before calling it. Has some Intel vs AT&T name overload hell: @@ -12697,6 +12725,38 @@ REP and REPZ also additionally stop if the comparison operation they repeat fail * REP: INS, OUTS, MOVS, LODS, and STOS * REPZ: CMPS and SCAS +==== x86 ENTER and LEAVE instructions + +link:userland/arch/x86_64/enter.S[] + +These instructions were designed to allocate and deallocate function stack frames in the prologue and epilogue: http://stackoverflow.com/questions/5959890/enter-vs-push-ebp-mov-ebp-esp-sub-esp-imm-and-leave-vs-mov-esp-ebp + +ENTER appears obsolete and is kept mostly for backwards compatibility. LEAVE is still emitted by some compilers. + +ENTER A, B is basically equivalent to: + +.... +push %rbp +mov %rsp, %rbp +sub %rsp, A +.... + +which implies an allocation of: + +* one dword to remember EBP +* A bytes for local function variables + +I didn't have the patience to study the B parameter, and it does not seem to be used often: http://stackoverflow.com/questions/26323215/do-any-languages-compilers-utilize-the-x86-enter-instruction-with-a-nonzero-ne + +LEAVE is equivalent to: + +.... +mov %rbp, %rsp +pop %rbp +.... + +which restores RSP and RBP to the values they had before the prologue. + === x86 miscellaneous instructions <> 5.1.13 "Miscellaneous Instructions" diff --git a/userland/arch/x86_64/enter.S b/userland/arch/x86_64/enter.S new file mode 100644 index 0000000..fc69358 --- /dev/null +++ b/userland/arch/x86_64/enter.S @@ -0,0 +1,23 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-enter-and-leave-instructions */ + +#include + +LKMC_PROLOGUE + /* Save values of interest before enter. */ + mov %rbp, %r12 + mov %rsp, %r13 + enter $16, $0 + mov %rsp, %r14 + + /* Restore stack so that we can do our assertions. */ + add $16, %rsp + leave + + /* ENTER pushed the stack down 24 bytes: + * + * * 8 due to `push %rbp` that `enter` does automatically + * * 16 due to `enter $16` + */ + sub %r14, %r13 + LKMC_ASSERT_EQ(%r13, $24) +LKMC_EPILOGUE diff --git a/userland/arch/x86_64/freestanding/linux/hello.S b/userland/arch/x86_64/freestanding/linux/hello.S index 9ae517c..9c7563c 100644 --- a/userland/arch/x86_64/freestanding/linux/hello.S +++ b/userland/arch/x86_64/freestanding/linux/hello.S @@ -19,4 +19,4 @@ asm_main_after_prologue: syscall msg: .ascii "hello\n" -len = . - msg + len = . - msg diff --git a/userland/arch/x86_64/freestanding/linux/int_system_call.S b/userland/arch/x86_64/freestanding/linux/int_system_call.S new file mode 100644 index 0000000..e728341 --- /dev/null +++ b/userland/arch/x86_64/freestanding/linux/int_system_call.S @@ -0,0 +1,26 @@ + /* https://github.com/cirosantilli/linux-kernel-module-cheat#linux-system-calls + * + * int $0x80 sycalls are still supported by x86_64 for some kind of backwards compatibility, + * (TODO so when x86_64 started it didn't have SYSCALL?) althoug you should prefre + * SYSCALL / VSDO. + * + * https://stackoverflow.com/questions/29440225/in-linux-x86-64-are-syscalls-and-int-0x80-related + */ + +.text +.global _start +_start: + /* write */ + mov $4, %rax + mov $1, %rbx + lea msg(%rip), %rcx + mov $len, %rdx + int $0x80 + + /* exit */ + mov $1, %rax + mov $0, %rbx + int $0x80 +msg: + .ascii "hello\n" + len = . - msg diff --git a/userland/arch/x86_64/push.S b/userland/arch/x86_64/push.S new file mode 100644 index 0000000..cde7acb --- /dev/null +++ b/userland/arch/x86_64/push.S @@ -0,0 +1,45 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-push-and-pop-instructions */ + +#include + +LKMC_PROLOGUE + /* register hello world. */ + mov %rsp, %r12 + mov $0x123456789ABCDEF0, %rax + push %rax + /* Save the stack delta. */ + sub %rsp, %r12 + /* Save the stack value. */ + mov (%rsp), %r13 + /* Restore the stack and save its value to R14. */ + pop %r14 + /* The stack still goes down by 8 even though we pushed a 4-byte immediate. */ + LKMC_ASSERT_EQ(%r12, $8) + LKMC_ASSERT_EQ(%r13, $0x123456789ABCDEF0) + LKMC_ASSERT_EQ(%r14, $0x123456789ABCDEF0) + + /* Immediate. Can only push up to 4 byte immediates. */ + mov %rsp, %r12 + push $0x12345678 + sub %rsp, %r12 + mov (%rsp), %r13 + pop %r14 + /* The stack still goes down by 8 even though we pushed a 4-byte immediate. */ + LKMC_ASSERT_EQ(%r12, $8) + LKMC_ASSERT_EQ(%r13, $0x12345678) + LKMC_ASSERT_EQ(%r14, $0x12345678) + + /* Word example. */ + mov %rsp, %r12 + mov $0x1234, %ax + push %ax + sub %rsp, %r12 + mov $0, %r13 + mov (%rsp), %r13w + mov $0, %r14 + pop %r14w + /* The stack was decremented only by 2 as expected. */ + LKMC_ASSERT_EQ(%r12, $2) + LKMC_ASSERT_EQ(%r13, $0x1234) + LKMC_ASSERT_EQ(%r14, $0x1234) +LKMC_EPILOGUE diff --git a/userland/arch/x86_64/pushf.S b/userland/arch/x86_64/pushf.S new file mode 100644 index 0000000..a8d5145 --- /dev/null +++ b/userland/arch/x86_64/pushf.S @@ -0,0 +1,57 @@ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#x86-data-transfer-instructions */ + +#include + +LKMC_PROLOGUE + /* First example. */ + + /* Clear carry flag. */ + clc + /* Save RSP before PUSHF. */ + mov %rsp, %r12 + pushf + /* Save stack value after PUSHF. Should contain the original FLAGS. */ + mov (%rsp), %r13 + /* Re-align stack to 16-bits for our asserts. */ + sub $8, %rsp + + /* The stack went down by 16: 8 from PUSHF, 8 from our SUB. */ + sub %rsp, %r12 + LKMC_ASSERT_EQ(%r12, $16) + + /* Check that bit 0 (Carry Flag) of R13 is clear. */ + bt $0, %r13 + LKMC_ASSERT(jnc) + + /* Restore the stack. */ + add $16, %rsp + + /* Now let's set carry flag instead. */ + stc + pushf + mov (%rsp), %r13 + sub $8, %rsp + bt $0, %r13 + /* Assert that it was pushed to stack set. */ + LKMC_ASSERT(jc) + add $16, %rsp + + /* POPF pops the stack into flags of course. */ + clc + pushf + stc + popf + LKMC_ASSERT(jnc) + + /* PUSHFQ has the same opcode as PUSHF in the Intel manual. + * which mentions that PUSHF can be requested with a prefix. + * + * GNU GAS 2.32 emits the same PUSHFQ code for both by default. + * according to objdump. + */ + clc + pushf + stc + popf + LKMC_ASSERT(jnc) +LKMC_EPILOGUE