asm: make use regular asserts that will just work on baremetal

Previously had wonky line pointer in asm_main. New interface simpler and more portable.

Add tests for ASSERT_EQ_ and family in arm and aarch64, previously on x86_64.

ASSERT_EQ_ and family in ARM can now either take =123, =addr or var, before this
the = was added on macros so var was not possible.

Define the main function directly in assembly, the C driver was useless.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-23 00:00:00 +00:00
parent 72200dee4e
commit c8c4f89854
90 changed files with 1003 additions and 978 deletions

View File

@@ -11647,7 +11647,7 @@ It is then a big copy paste for most other data instructions.
Then, modify that program to make the assertion fail: Then, modify that program to make the assertion fail:
.... ....
ASSERT_EQ(%rax, $4) LKMC_ASSERT_EQ(%rax, $4)
.... ....
because 1 + 2 tends to equal 3 instead of 4. because 1 + 2 tends to equal 3 instead of 4.
@@ -11676,10 +11676,16 @@ and notice how the error message gives both:
Other infrastructure sanity checks that you might want to look into include: Other infrastructure sanity checks that you might want to look into include:
* link:userland/arch/empty.S[] * link:userland/arch/empty.S[]
* `FAIL` tests * `LKMC_FAIL` tests
** link:userland/arch/fail.S[] ** link:userland/arch/fail.S[]
* `ASSERT_MEMCMP` tests * `LKMC_ASSERT_EQ` tests
** link:userland/arch/x86_64/lkmc_assert_eq_fail.S[]
** link:userland/arch/arm/lkmc_assert_eq_fail.S[]
** link:userland/arch/aarch64/lkmc_assert_eq_fail.S[]
* `LKMC_ASSERT_MEMCMP` tests
** link:userland/arch/x86_64/lkmc_assert_memcmp_fail.S[] ** link:userland/arch/x86_64/lkmc_assert_memcmp_fail.S[]
** link:userland/arch/arm/lkmc_assert_memcmp_fail.S[]
** link:userland/arch/aarch64/lkmc_assert_memcmp_fail.S[]
=== Assembly registers === Assembly registers
@@ -11799,13 +11805,13 @@ This allows using the C standard library for IO, which is very convenient and po
It also exposes other non-IO functionality that is very convenient such as `memcmp`. It also exposes other non-IO functionality that is very convenient such as `memcmp`.
The C standard library infrastructure is implemented in the following files: The C standard library infrastructure is implemented in the common userland / baremetal source files:
* link:userland/arch/main.c[] * link:lkmc.c[]
* link:userland/arch/common.h[] * link:lkmc.h[]
* link:userland/arch/x86_64/common_arch.h[] * link:lkmc/aarch64.h[]
* link:userland/arch/arm/common_arch.h[] * link:lkmc/arm.h[]
* link:userland/arch/aarch64/common_arch.h[] * link:lkmc/x86_64.h[]
==== Freestanding programs ==== Freestanding programs
@@ -11914,23 +11920,51 @@ Questions about the C inline assembly examples:
* x86_64: https://stackoverflow.com/questions/9506353/how-to-invoke-a-system-call-via-sysenter-in-inline-assembly/54956854#54956854 * x86_64: https://stackoverflow.com/questions/9506353/how-to-invoke-a-system-call-via-sysenter-in-inline-assembly/54956854#54956854
* ARM: https://stackoverflow.com/questions/21729497/doing-a-syscall-without-libc-using-arm-inline-assembly * ARM: https://stackoverflow.com/questions/21729497/doing-a-syscall-without-libc-using-arm-inline-assembly
=== Calling conventions === Linux calling conventions
Summary:
[options="header"]
|===
|arch |arguments |return value |callee saved registers
|x86_64
|rdi, rsi, rdx, rcx, r8, r9, xmm07
|rax, rdx
|rbx, rbp, r12r15
|arm
|r0-r3
|r0-r3
|r4-r11
|aarch64
|x0-x7
|x0-x7
|x19-x29
|===
==== x86_64 calling convention ==== x86_64 calling convention
Examples: Examples:
* link:userland/arch/x86_64/common_arch.h[] `ENTRY` and `EXIT` * link:lkmc/x86_64.h[] `ENTRY` and `EXIT`
Bibliography:
* https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI
* https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call/55207335#55207335
==== ARM calling convention ==== ARM calling convention
Call C standard library functions from assembly and vice versa. Call C standard library functions from assembly and vice versa.
* arm * arm
** link:userland/arch/arm/common_arch.h[] `ENTRY` and `EXIT` ** link:lkmc/arm.h[] `ENTRY` and `EXIT`
** link:userland/arch/arm/linux/c_from_asm.S[] ** link:userland/arch/arm/linux/c_from_asm.S[]
* aarch64 * aarch64
** link:userland/arch/aarch64/common_arch.h[] `ENTRY` and `EXIT` ** link:lkmc/aarch64.h[] `ENTRY` and `EXIT`
** link:userland/arch/aarch64/c/linux/asm_from_c.c[] ** link:userland/arch/aarch64/c/linux/asm_from_c.c[]
ARM Architecture Procedure Call Standard (AAPCS) is the name that ARM Holdings gives to the calling convention. ARM Architecture Procedure Call Standard (AAPCS) is the name that ARM Holdings gives to the calling convention.
@@ -12685,7 +12719,7 @@ Guaranteed undefined! Therefore raise illegal instruction signal. Used by GCC `_
* link:userland/arch/arm/udf.S[] * link:userland/arch/arm/udf.S[]
* link:userland/arch/aarch64/udf.S[] * link:userland/arch/aarch64/udf.S[]
Why GNU GAS 2.29 does not have a mnemonic for it in A64 because it is very recent: shows in [[armarm8-db]] but not `ca`. Why GNU GAS 2.29 does not have a mnemonic for it in A64 because it is very recent: shows in <<armarm8-db>> but not `ca`.
=== ARM SIMD === ARM SIMD

View File

@@ -60,25 +60,6 @@ Default: build all examples that have their package dependencies met, e.g.:
extra_deps=[self.env['common_h']], extra_deps=[self.env['common_h']],
link=False, link=False,
) )
extra_obj_userland_asm = os.path.join(
build_dir,
'arch',
'main' + self.env['obj_ext']
)
extra_obj_userland_asm_relpath = os.path.join(
'arch',
'main' + self.env['c_ext']
)
self._build_one(
in_path=os.path.join(
self.env['userland_source_dir'],
extra_obj_userland_asm_relpath
),
out_path=extra_obj_userland_asm,
cc_flags=cc_flags,
extra_deps=[self.env['common_h']],
link=False,
)
with thread_pool.ThreadPool( with thread_pool.ThreadPool(
self._build_one, self._build_one,
nthreads=self.env['nproc'], nthreads=self.env['nproc'],
@@ -94,7 +75,6 @@ Default: build all examples that have their package dependencies met, e.g.:
my_thread_pool.submit({ my_thread_pool.submit({
'cc_flags': cc_flags, 'cc_flags': cc_flags,
'extra_objs_lkmc_common': [extra_obj_lkmc_common], 'extra_objs_lkmc_common': [extra_obj_lkmc_common],
'extra_objs_userland_asm': [extra_obj_userland_asm],
'in_path': in_path, 'in_path': in_path,
'out_path': self.resolve_userland_executable(in_path), 'out_path': self.resolve_userland_executable(in_path),
}) })

View File

@@ -1497,8 +1497,6 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-debug-build
if link: if link:
if my_path_properties['extra_objs_lkmc_common']: if my_path_properties['extra_objs_lkmc_common']:
extra_objs.extend(extra_objs_lkmc_common) extra_objs.extend(extra_objs_lkmc_common)
if my_path_properties['extra_objs_userland_asm']:
extra_objs.extend(extra_objs_userland_asm)
if my_path_properties['extra_objs_baremetal_bootloader']: if my_path_properties['extra_objs_baremetal_bootloader']:
extra_objs.extend(extra_objs_baremetal_bootloader) extra_objs.extend(extra_objs_baremetal_bootloader)
if self.need_rebuild([in_path] + extra_objs + extra_deps, out_path): if self.need_rebuild([in_path] + extra_objs + extra_deps, out_path):
@@ -1518,12 +1516,7 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#gem5-debug-build
if dirpath_relative_root_components_len > 0: if dirpath_relative_root_components_len > 0:
if dirpath_relative_root_components[0] == 'userland': if dirpath_relative_root_components[0] == 'userland':
if dirpath_relative_root_components_len > 1: if dirpath_relative_root_components_len > 1:
if dirpath_relative_root_components[1] == 'arch': if dirpath_relative_root_components[1] == 'libs':
cc_flags.extend([
'-I', os.path.join(self.env['userland_source_arch_arch_dir']), LF,
'-I', os.path.join(self.env['userland_source_arch_dir']), LF,
])
elif dirpath_relative_root_components[1] == 'libs':
if dirpath_relative_root_components_len > 1: if dirpath_relative_root_components_len > 1:
if self.env['gcc_which'] == 'host': if self.env['gcc_which'] == 'host':
eigen_root = '/' eigen_root = '/'

50
lkmc.c
View File

@@ -2,10 +2,60 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <lkmc.h> #include <lkmc.h>
#define LKMC_ASSERT_EQ_DEFINE(bits) \
LKMC_ASSERT_EQ_DECLARE(bits) \
{ \
if (val1 != val2) { \
printf("%s failed\n", __func__); \
printf("val1 0x%" PRIX ## bits "\n", val1); \
printf("val2 0x%" PRIX ## bits "\n", val2); \
lkmc_assert_fail(line); \
} \
}
LKMC_ASSERT_EQ_DEFINE(32)
LKMC_ASSERT_EQ_DEFINE(64)
#undef ASSERT_EQ_DEFINE
void lkmc_assert_fail(uint32_t line) {
printf("error: assertion failed at line: %" PRIu32 "\n", line);
exit(1);
}
void lkmc_assert_memcmp(
const void *s1,
const void *s2,
size_t n,
uint32_t line
) {
size_t i;
uint8_t *s1b, *s2b;
uint8_t b1, b2;
s1b = (uint8_t *)s1;
s2b = (uint8_t *)s2;
for (i = 0; i < n; ++i) {
b1 = s1b[i];
b2 = s2b[i];
if (b1 != b2) {
printf(
"%s failed: "
"byte1, byte2, index: "
"0x%02" PRIX8 " 0x%02" PRIX8 " 0x%zX\n",
__func__,
b1,
b2,
i
);
lkmc_assert_fail(line);
}
}
}
void lkmc_baremetal_on_exit_callback(int status, void *arg) { void lkmc_baremetal_on_exit_callback(int status, void *arg) {
(void)arg; (void)arg;
if (status != 0) { if (status != 0) {

267
lkmc.h
View File

@@ -3,17 +3,33 @@
#ifndef LKMC_H #ifndef LKMC_H
#define LKMC_H #define LKMC_H
/* Common C definitions. */
#define LKMC_UNUSED(x) (void)x
#if !defined(__ASSEMBLER__) #if !defined(__ASSEMBLER__)
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define LKMC_ASSERT_EQ_DECLARE(bits) \
void lkmc_assert_eq_ ## bits( \
uint ## bits ## _t val1, \
uint ## bits ## _t val2, \
uint32_t line \
)
LKMC_ASSERT_EQ_DECLARE(32);
LKMC_ASSERT_EQ_DECLARE(64);
void lkmc_assert_fail(uint32_t line);
void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line);
void lkmc_baremetal_on_exit_callback(int status, void *arg); void lkmc_baremetal_on_exit_callback(int status, void *arg);
#endif #endif
/* Assert that the given branch instruction is taken. */
#define LKMC_ASSERT(branch_if_pass) \
branch_if_pass 1f; \
LKMC_ASSERT_FAIL; \
1: \
;
/* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */ /* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */
#define LKMC_CONCAT_EVAL(a,b) a ## b #define LKMC_CONCAT_EVAL(a,b) a ## b
#define LKMC_CONCAT(a,b) LKMC_CONCAT_EVAL(a, b) #define LKMC_CONCAT(a,b) LKMC_CONCAT_EVAL(a, b)
@@ -22,6 +38,9 @@ void lkmc_baremetal_on_exit_callback(int status, void *arg);
.global name; \ .global name; \
name: name:
/* Common C definitions. */
#define LKMC_UNUSED(x) (void)x
/* Weak means that if any other file defines it as a non-weak global, /* Weak means that if any other file defines it as a non-weak global,
* that one will take precedence: * that one will take precedence:
* https://stackoverflow.com/questions/274753/how-to-make-weak-linking-work-with-gcc/54601464#54601464 * https://stackoverflow.com/questions/274753/how-to-make-weak-linking-work-with-gcc/54601464#54601464
@@ -30,238 +49,14 @@ void lkmc_baremetal_on_exit_callback(int status, void *arg);
.weak name; \ .weak name; \
name: name:
/* aarch64 specifics. */ #if defined(__x86_64__)
#if defined(__aarch64__) #include <lkmc/x86_64.h>
#elif defined(__arm__)
/* LKMC_VECTOR_TABLE #include <lkmc/arm.h>
* #elif defined(__aarch64__)
* Adapted from: https://github.com/takeharukato/sample-tsk-sw/blob/ce7973aa5d46c9eedb58309de43df3b09d4f8d8d/hal/aarch64/vector.S #include <lkmc/aarch64.h>
*/ #else
#error
#define LKMC_VECTOR_SYNC_SP0 (0x1) #endif
#define LKMC_VECTOR_IRQ_SP0 (0x2)
#define LKMC_VECTOR_FIQ_SP0 (0x3)
#define LKMC_VECTOR_SERR_SP0 (0x4)
#define LKMC_VECTOR_SYNC_SPX (0x11)
#define LKMC_VECTOR_IRQ_SPX (0x12)
#define LKMC_VECTOR_FIQ_SPX (0x13)
#define LKMC_VECTOR_SERR_SPX (0x14)
#define LKMC_VECTOR_SYNC_AARCH64 (0x21)
#define LKMC_VECTOR_IRQ_AARCH64 (0x22)
#define LKMC_VECTOR_FIQ_AARCH64 (0x23)
#define LKMC_VECTOR_SERR_AARCH64 (0x24)
#define LKMC_VECTOR_SYNC_AARCH32 (0x31)
#define LKMC_VECTOR_IRQ_AARCH32 (0x32)
#define LKMC_VECTOR_FIQ_AARCH32 (0x33)
#define LKMC_VECTOR_SERR_AARCH32 (0x34)
#define LKMC_VECTOR_EXC_FRAME_SIZE (288) /* sizeof(lkmc_vector_exception_frame) */
#define LKMC_VECTOR_EXC_EXC_TYPE_OFFSET (0) /* offsetof(lkmc_vector_exception_frame, exc_type) */
#define LKMC_VECTOR_EXC_EXC_ESR_OFFSE (8) /* offsetof(lkmc_vector_exception_frame, exc_esr) */
#define LKMC_VECTOR_EXC_EXC_SP_OFFSET (16) /* offsetof(lkmc_vector_exception_frame, exc_sp) */
#define LKMC_VECTOR_EXC_EXC_ELR_OFFSET (24) /* offsetof(lkmc_vector_exception_frame, exc_elr) */
#define LKMC_VECTOR_EXC_EXC_SPSR_OFFSET (32) /* offsetof(lkmc_vector_exception_frame, exc_spsr) */
#define LKMC_VECTOR_FUNC_ALIGN .align 2
#define LKMC_VECTOR_SYMBOL_PREFIX lkmc_vector_
#define LKMC_VECTOR_BUILD_TRAPFRAME(exc_type) \
stp x29, x30, [sp, -16]!; \
stp x27, x28, [sp, -16]!; \
stp x25, x26, [sp, -16]!; \
stp x23, x24, [sp, -16]!; \
stp x21, x22, [sp, -16]!; \
stp x19, x20, [sp, -16]!; \
stp x17, x18, [sp, -16]!; \
stp x15, x16, [sp, -16]!; \
stp x13, x14, [sp, -16]!; \
stp x11, x12, [sp, -16]!; \
stp x9, x10, [sp, -16]!; \
stp x7, x8, [sp, -16]!; \
stp x5, x6, [sp, -16]!; \
stp x3, x4, [sp, -16]!; \
stp x1, x2, [sp, -16]!; \
mrs x21, spsr_el1; \
stp x21, x0, [sp, -16]!; \
mrs x21, elr_el1; \
stp xzr, x21, [sp, -16]!; \
mov x21, exc_type; \
mrs x22, esr_el1; \
stp x21, x22, [sp, -16]!
#define LKMC_VECTOR_STORE_TRAPED_SP \
mrs x21, sp_el0; \
str x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]
#define LKMC_VECTOR_CALL_TRAP_HANDLER \
mov x0, sp; \
bl lkmc_vector_trap_handler
#define LKMC_VECTOR_STORE_NESTED_SP \
mov x21, sp; \
add x21, x21, LKMC_VECTOR_EXC_FRAME_SIZE; \
str x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]
#define LKMC_VECTOR_RESTORE_TRAPED_SP \
ldr x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]; \
msr sp_el0, x21
#define LKMC_VECTOR_RESTORE_TRAPFRAME \
add sp, sp, 16; \
ldp x21, x22, [sp], 16; \
msr elr_el1, x22; \
ldp x21, x0, [sp], 16; \
msr spsr_el1, x21; \
ldp x1, x2, [sp], 16; \
ldp x3, x4, [sp], 16; \
ldp x5, x6, [sp], 16; \
ldp x7, x8, [sp], 16; \
ldp x9, x10, [sp], 16; \
ldp x11, x12, [sp], 16; \
ldp x13, x14, [sp], 16; \
ldp x15, x16, [sp], 16; \
ldp x17, x18, [sp], 16; \
ldp x19, x20, [sp], 16; \
ldp x21, x22, [sp], 16; \
ldp x23, x24, [sp], 16; \
ldp x25, x26, [sp], 16; \
ldp x27, x28, [sp], 16; \
ldp x29, x30, [sp], 16; \
eret
#define LKMC_VECTOR_ENTRY(func_name) \
.align 7; \
b LKMC_VECTOR_SYMBOL_PREFIX ## func_name
#define LKMC_VECTOR_FUNC(func_name, func_id) \
LKMC_VECTOR_FUNC_ALIGN; \
LKMC_VECTOR_SYMBOL_PREFIX ## func_name:; \
LKMC_VECTOR_BUILD_TRAPFRAME(func_id); \
LKMC_VECTOR_STORE_TRAPED_SP; \
LKMC_VECTOR_CALL_TRAP_HANDLER; \
LKMC_VECTOR_RESTORE_TRAPED_SP; \
LKMC_VECTOR_RESTORE_TRAPFRAME
#define LKMC_VECTOR_FUNC_NESTED(func_name, func_id) \
LKMC_VECTOR_FUNC_ALIGN; \
LKMC_VECTOR_SYMBOL_PREFIX ## func_name:; \
LKMC_VECTOR_BUILD_TRAPFRAME(func_id); \
LKMC_VECTOR_STORE_NESTED_SP; \
LKMC_VECTOR_CALL_TRAP_HANDLER; \
LKMC_VECTOR_RESTORE_TRAPFRAME
/* Define the actual vector table. */
#define LKMC_VECTOR_TABLE \
.align 11; \
LKMC_GLOBAL(lkmc_vector_table); \
; \
LKMC_VECTOR_ENTRY(curr_el_sp0_sync); \
LKMC_VECTOR_ENTRY(curr_el_sp0_irq); \
LKMC_VECTOR_ENTRY(curr_el_sp0_fiq); \
LKMC_VECTOR_ENTRY(curr_el_sp0_serror); \
; \
LKMC_VECTOR_ENTRY(curr_el_spx_sync); \
LKMC_VECTOR_ENTRY(curr_el_spx_irq); \
LKMC_VECTOR_ENTRY(curr_el_spx_fiq); \
LKMC_VECTOR_ENTRY(curr_el_spx_serror); \
; \
LKMC_VECTOR_ENTRY(lower_el_aarch64_sync); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_irq); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_fiq); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_serror); \
; \
LKMC_VECTOR_ENTRY(lower_el_aarch32_sync); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_irq); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_fiq); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_serror); \
; \
LKMC_VECTOR_FUNC(curr_el_sp0_sync, LKMC_VECTOR_SYNC_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_irq, LKMC_VECTOR_IRQ_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_fiq, LKMC_VECTOR_FIQ_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_serror, LKMC_VECTOR_SERR_SP0); \
; \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_sync, LKMC_VECTOR_SYNC_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_irq, LKMC_VECTOR_IRQ_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_fiq, LKMC_VECTOR_FIQ_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_serror, LKMC_VECTOR_SERR_SPX); \
; \
LKMC_VECTOR_FUNC(lower_el_aarch64_sync, LKMC_VECTOR_SYNC_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_irq, LKMC_VECTOR_IRQ_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_fiq, LKMC_VECTOR_FIQ_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_serror, LKMC_VECTOR_SERR_AARCH64); \
; \
LKMC_VECTOR_FUNC(lower_el_aarch32_sync, LKMC_VECTOR_SYNC_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_irq, LKMC_VECTOR_IRQ_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_fiq, LKMC_VECTOR_FIQ_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_serror, LKMC_VECTOR_SERR_AARCH32)
/* aarch64 C definitions. */
#if !defined(__ASSEMBLER__)
#include <stdint.h>
typedef struct {
uint64_t exc_type;
uint64_t exc_esr;
uint64_t exc_sp;
uint64_t exc_elr;
uint64_t exc_spsr;
uint64_t x0;
uint64_t x1;
uint64_t x2;
uint64_t x3;
uint64_t x4;
uint64_t x5;
uint64_t x6;
uint64_t x7;
uint64_t x8;
uint64_t x9;
uint64_t x10;
uint64_t x11;
uint64_t x12;
uint64_t x13;
uint64_t x14;
uint64_t x15;
uint64_t x16;
uint64_t x17;
uint64_t x18;
uint64_t x19;
uint64_t x20;
uint64_t x21;
uint64_t x22;
uint64_t x23;
uint64_t x24;
uint64_t x25;
uint64_t x26;
uint64_t x27;
uint64_t x28;
uint64_t x29;
uint64_t x30;
} LkmcVectorExceptionFrame;
void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception);
#define LKMC_SVC(immediate) __asm__ __volatile__("svc " #immediate : : : )
#define LKMC_SYSREG_SYMBOL_PREFIX lkmc_sysreg_
#define LKMC_SYSREG_READ_WRITE(type, name) \
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read)(void); \
void LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _write)(type name);
#define LKMC_SYSREG_OPS \
LKMC_SYSREG_READ_WRITE(uint32_t, cntv_ctl_el0) \
LKMC_SYSREG_READ_WRITE(uint32_t, daif) \
LKMC_SYSREG_READ_WRITE(uint32_t, spsel) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntfrq_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntv_cval_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntv_tval_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntvct_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, sp_el1) \
LKMC_SYSREG_READ_WRITE(uint64_t, vbar_el1)
LKMC_SYSREG_OPS
#undef LKMC_SYSREG_READ_WRITE
#endif #endif
#endif
#endif

299
lkmc/aarch64.h Normal file
View File

@@ -0,0 +1,299 @@
#ifndef LKMC_AARCH64_H
#define LKMC_AARCH64_H
#define LKMC_ASSERT_EQ(reg, const) \
mov x0, reg; \
ldr x1, const; \
ldr w2, =__LINE__; \
bl lkmc_assert_eq_64; \
;
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
str reg2, [sp, -16]!; \
mov x0, reg1; \
ldr x1, [sp], 16; \
ldr w2, =__LINE__; \
bl lkmc_assert_eq_64; \
;
#define LKMC_ASSERT_EQ_REG_32(reg1, reg2) \
str reg2, [sp, -4]!; \
mov w0, reg1; \
ldr w1, [sp], 4; \
ldr w2, =__LINE__; \
bl lkmc_assert_eq_32; \
;
#define LKMC_ASSERT_FAIL \
ldr w0, =__LINE__; \
bl lkmc_assert_fail; \
;
#define LKMC_ASSERT_MEMCMP(label1, label2, size) \
adr x0, label1; \
adr x1, label2; \
ldr x2, size; \
ldr x3, =__LINE__; \
bl lkmc_assert_memcmp; \
;
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-calling-convention */
#define LKMC_EPILOGUE \
ldp x19, x20, [sp, 0x50]; \
ldp x21, x22, [sp, 0x40]; \
ldp x23, x24, [sp, 0x30]; \
ldp x25, x26, [sp, 0x20]; \
ldp x27, x28, [sp, 0x10]; \
ldp x29, x30, [sp]; \
add sp, sp, 0x60; \
mov x0, 0; \
ret; \
;
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-calling-convention */
#define LKMC_PROLOGUE \
.text; \
.global main; \
main: \
sub sp, sp, 0x60; \
stp x29, x30, [sp]; \
stp x27, x28, [sp, 0x10]; \
stp x25, x26, [sp, 0x20]; \
stp x23, x24, [sp, 0x30]; \
stp x21, x22, [sp, 0x40]; \
stp x19, x20, [sp, 0x50]; \
main_after_prologue: \
;
/* LKMC_VECTOR_TABLE
*
* Adapted from: https://github.com/takeharukato/sample-tsk-sw/blob/ce7973aa5d46c9eedb58309de43df3b09d4f8d8d/hal/aarch64/vector.S
*/
#define LKMC_VECTOR_SYNC_SP0 (0x1)
#define LKMC_VECTOR_IRQ_SP0 (0x2)
#define LKMC_VECTOR_FIQ_SP0 (0x3)
#define LKMC_VECTOR_SERR_SP0 (0x4)
#define LKMC_VECTOR_SYNC_SPX (0x11)
#define LKMC_VECTOR_IRQ_SPX (0x12)
#define LKMC_VECTOR_FIQ_SPX (0x13)
#define LKMC_VECTOR_SERR_SPX (0x14)
#define LKMC_VECTOR_SYNC_AARCH64 (0x21)
#define LKMC_VECTOR_IRQ_AARCH64 (0x22)
#define LKMC_VECTOR_FIQ_AARCH64 (0x23)
#define LKMC_VECTOR_SERR_AARCH64 (0x24)
#define LKMC_VECTOR_SYNC_AARCH32 (0x31)
#define LKMC_VECTOR_IRQ_AARCH32 (0x32)
#define LKMC_VECTOR_FIQ_AARCH32 (0x33)
#define LKMC_VECTOR_SERR_AARCH32 (0x34)
#define LKMC_VECTOR_EXC_FRAME_SIZE (288) /* sizeof(lkmc_vector_exception_frame) */
#define LKMC_VECTOR_EXC_EXC_TYPE_OFFSET (0) /* offsetof(lkmc_vector_exception_frame, exc_type) */
#define LKMC_VECTOR_EXC_EXC_ESR_OFFSE (8) /* offsetof(lkmc_vector_exception_frame, exc_esr) */
#define LKMC_VECTOR_EXC_EXC_SP_OFFSET (16) /* offsetof(lkmc_vector_exception_frame, exc_sp) */
#define LKMC_VECTOR_EXC_EXC_ELR_OFFSET (24) /* offsetof(lkmc_vector_exception_frame, exc_elr) */
#define LKMC_VECTOR_EXC_EXC_SPSR_OFFSET (32) /* offsetof(lkmc_vector_exception_frame, exc_spsr) */
#define LKMC_VECTOR_FUNC_ALIGN .align 2
#define LKMC_VECTOR_SYMBOL_PREFIX lkmc_vector_
#define LKMC_VECTOR_BUILD_TRAPFRAME(exc_type) \
stp x29, x30, [sp, -16]!; \
stp x27, x28, [sp, -16]!; \
stp x25, x26, [sp, -16]!; \
stp x23, x24, [sp, -16]!; \
stp x21, x22, [sp, -16]!; \
stp x19, x20, [sp, -16]!; \
stp x17, x18, [sp, -16]!; \
stp x15, x16, [sp, -16]!; \
stp x13, x14, [sp, -16]!; \
stp x11, x12, [sp, -16]!; \
stp x9, x10, [sp, -16]!; \
stp x7, x8, [sp, -16]!; \
stp x5, x6, [sp, -16]!; \
stp x3, x4, [sp, -16]!; \
stp x1, x2, [sp, -16]!; \
mrs x21, spsr_el1; \
stp x21, x0, [sp, -16]!; \
mrs x21, elr_el1; \
stp xzr, x21, [sp, -16]!; \
mov x21, exc_type; \
mrs x22, esr_el1; \
stp x21, x22, [sp, -16]!
#define LKMC_VECTOR_STORE_TRAPED_SP \
mrs x21, sp_el0; \
str x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]
#define LKMC_VECTOR_CALL_TRAP_HANDLER \
mov x0, sp; \
bl lkmc_vector_trap_handler
#define LKMC_VECTOR_STORE_NESTED_SP \
mov x21, sp; \
add x21, x21, LKMC_VECTOR_EXC_FRAME_SIZE; \
str x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]
#define LKMC_VECTOR_RESTORE_TRAPED_SP \
ldr x21, [sp, LKMC_VECTOR_EXC_EXC_SP_OFFSET]; \
msr sp_el0, x21
#define LKMC_VECTOR_RESTORE_TRAPFRAME \
add sp, sp, 16; \
ldp x21, x22, [sp], 16; \
msr elr_el1, x22; \
ldp x21, x0, [sp], 16; \
msr spsr_el1, x21; \
ldp x1, x2, [sp], 16; \
ldp x3, x4, [sp], 16; \
ldp x5, x6, [sp], 16; \
ldp x7, x8, [sp], 16; \
ldp x9, x10, [sp], 16; \
ldp x11, x12, [sp], 16; \
ldp x13, x14, [sp], 16; \
ldp x15, x16, [sp], 16; \
ldp x17, x18, [sp], 16; \
ldp x19, x20, [sp], 16; \
ldp x21, x22, [sp], 16; \
ldp x23, x24, [sp], 16; \
ldp x25, x26, [sp], 16; \
ldp x27, x28, [sp], 16; \
ldp x29, x30, [sp], 16; \
eret
#define LKMC_VECTOR_ENTRY(func_name) \
.align 7; \
b LKMC_VECTOR_SYMBOL_PREFIX ## func_name
#define LKMC_VECTOR_FUNC(func_name, func_id) \
LKMC_VECTOR_FUNC_ALIGN; \
LKMC_VECTOR_SYMBOL_PREFIX ## func_name:; \
LKMC_VECTOR_BUILD_TRAPFRAME(func_id); \
LKMC_VECTOR_STORE_TRAPED_SP; \
LKMC_VECTOR_CALL_TRAP_HANDLER; \
LKMC_VECTOR_RESTORE_TRAPED_SP; \
LKMC_VECTOR_RESTORE_TRAPFRAME
#define LKMC_VECTOR_FUNC_NESTED(func_name, func_id) \
LKMC_VECTOR_FUNC_ALIGN; \
LKMC_VECTOR_SYMBOL_PREFIX ## func_name:; \
LKMC_VECTOR_BUILD_TRAPFRAME(func_id); \
LKMC_VECTOR_STORE_NESTED_SP; \
LKMC_VECTOR_CALL_TRAP_HANDLER; \
LKMC_VECTOR_RESTORE_TRAPFRAME
/* Define the actual vector table. */
#define LKMC_VECTOR_TABLE \
.align 11; \
LKMC_GLOBAL(lkmc_vector_table); \
; \
LKMC_VECTOR_ENTRY(curr_el_sp0_sync); \
LKMC_VECTOR_ENTRY(curr_el_sp0_irq); \
LKMC_VECTOR_ENTRY(curr_el_sp0_fiq); \
LKMC_VECTOR_ENTRY(curr_el_sp0_serror); \
; \
LKMC_VECTOR_ENTRY(curr_el_spx_sync); \
LKMC_VECTOR_ENTRY(curr_el_spx_irq); \
LKMC_VECTOR_ENTRY(curr_el_spx_fiq); \
LKMC_VECTOR_ENTRY(curr_el_spx_serror); \
; \
LKMC_VECTOR_ENTRY(lower_el_aarch64_sync); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_irq); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_fiq); \
LKMC_VECTOR_ENTRY(lower_el_aarch64_serror); \
; \
LKMC_VECTOR_ENTRY(lower_el_aarch32_sync); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_irq); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_fiq); \
LKMC_VECTOR_ENTRY(lower_el_aarch32_serror); \
; \
LKMC_VECTOR_FUNC(curr_el_sp0_sync, LKMC_VECTOR_SYNC_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_irq, LKMC_VECTOR_IRQ_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_fiq, LKMC_VECTOR_FIQ_SP0); \
LKMC_VECTOR_FUNC(curr_el_sp0_serror, LKMC_VECTOR_SERR_SP0); \
; \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_sync, LKMC_VECTOR_SYNC_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_irq, LKMC_VECTOR_IRQ_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_fiq, LKMC_VECTOR_FIQ_SPX); \
LKMC_VECTOR_FUNC_NESTED(curr_el_spx_serror, LKMC_VECTOR_SERR_SPX); \
; \
LKMC_VECTOR_FUNC(lower_el_aarch64_sync, LKMC_VECTOR_SYNC_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_irq, LKMC_VECTOR_IRQ_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_fiq, LKMC_VECTOR_FIQ_AARCH64); \
LKMC_VECTOR_FUNC(lower_el_aarch64_serror, LKMC_VECTOR_SERR_AARCH64); \
; \
LKMC_VECTOR_FUNC(lower_el_aarch32_sync, LKMC_VECTOR_SYNC_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_irq, LKMC_VECTOR_IRQ_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_fiq, LKMC_VECTOR_FIQ_AARCH32); \
LKMC_VECTOR_FUNC(lower_el_aarch32_serror, LKMC_VECTOR_SERR_AARCH32)
/* aarch64 C definitions. */
#if !defined(__ASSEMBLER__)
#include <stdint.h>
typedef struct {
uint64_t exc_type;
uint64_t exc_esr;
uint64_t exc_sp;
uint64_t exc_elr;
uint64_t exc_spsr;
uint64_t x0;
uint64_t x1;
uint64_t x2;
uint64_t x3;
uint64_t x4;
uint64_t x5;
uint64_t x6;
uint64_t x7;
uint64_t x8;
uint64_t x9;
uint64_t x10;
uint64_t x11;
uint64_t x12;
uint64_t x13;
uint64_t x14;
uint64_t x15;
uint64_t x16;
uint64_t x17;
uint64_t x18;
uint64_t x19;
uint64_t x20;
uint64_t x21;
uint64_t x22;
uint64_t x23;
uint64_t x24;
uint64_t x25;
uint64_t x26;
uint64_t x27;
uint64_t x28;
uint64_t x29;
uint64_t x30;
} LkmcVectorExceptionFrame;
void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception);
#define LKMC_SVC(immediate) __asm__ __volatile__("svc " #immediate : : : )
#define LKMC_SYSREG_SYMBOL_PREFIX lkmc_sysreg_
#define LKMC_SYSREG_READ_WRITE(type, name) \
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read)(void); \
void LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _write)(type name);
#define LKMC_SYSREG_OPS \
LKMC_SYSREG_READ_WRITE(uint32_t, cntv_ctl_el0) \
LKMC_SYSREG_READ_WRITE(uint32_t, daif) \
LKMC_SYSREG_READ_WRITE(uint32_t, spsel) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntfrq_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntv_cval_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntv_tval_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, cntvct_el0) \
LKMC_SYSREG_READ_WRITE(uint64_t, sp_el1) \
LKMC_SYSREG_READ_WRITE(uint64_t, vbar_el1)
LKMC_SYSREG_OPS
#undef LKMC_SYSREG_READ_WRITE
#endif
#endif

53
lkmc/arm.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef LKMC_ARM_H
#define LKMC_ARM_H
#if defined(__ASSEMBLER__)
.syntax unified
#endif
#define LKMC_ASSERT_EQ(reg, const) \
mov r0, reg; \
ldr r1, const; \
ldr r2, =__LINE__; \
bl lkmc_assert_eq_32; \
;
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
str reg2, [sp, -4]!; \
mov r0, reg1; \
ldr r1, [sp], 4; \
ldr r2, =__LINE__; \
bl lkmc_assert_eq_32; \
;
#define LKMC_ASSERT_FAIL \
ldr r0, =__LINE__; \
bl lkmc_assert_fail; \
;
#define LKMC_ASSERT_MEMCMP(label1, label2, size) \
ldr r0, =label1; \
ldr r1, =label2; \
ldr r2, size; \
ldr r3, =__LINE__; \
bl lkmc_assert_memcmp; \
;
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-calling-convention */
#define LKMC_EPILOGUE \
add sp, 16; \
ldmia sp!, {r4-r12, lr}; \
mov r0, 0; \
bx lr; \
;
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-calling-convention */
#define LKMC_PROLOGUE \
.text; \
.global main; \
main: \
stmdb sp!, {r0-r12, lr}; \
main_after_prologue: \
;
#endif

62
lkmc/x86_64.h Normal file
View File

@@ -0,0 +1,62 @@
#ifndef LKMC_X86_64_H
#define LKMC_X86_64_H
/* This and other macros may make C function calls, and therefore can destroy
* non-callee saved registers. */
#define LKMC_ASSERT_EQ(general1, general2) \
mov general2, %rdi; \
push %rdi; \
mov general1, %rdi; \
pop %rsi; \
mov $__LINE__, %edx; \
call lkmc_assert_eq_64; \
;
#define LKMC_ASSERT_FAIL \
mov $__LINE__, %edi; \
call lkmc_assert_fail; \
;
/* Assert that two memory arrays are the same. */
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
lea label1(%rip), %rdi; \
lea label2(%rip), %rsi; \
mov const_size, %rdx; \
mov $__LINE__, %ecx; \
call lkmc_assert_memcmp; \
;
/* Function epilogue.
*
* https://github.com/cirosantilli/linux-kernel-module-cheat#x86_64-calling-convention
*/
#define LKMC_EPILOGUE \
pop %rbx; \
pop %r12; \
pop %r13; \
pop %r14; \
pop %r15; \
pop %rbp; \
mov $0, %rax; \
ret; \
;
/* Function prologue.
*
* https://github.com/cirosantilli/linux-kernel-module-cheat#x86_64-calling-convention
*/
#define LKMC_PROLOGUE \
.text; \
.global main; \
main: \
push %rbp; \
mov %rsp, %rbp; \
push %r15; \
push %r14; \
push %r13; \
push %r12; \
push %rbx; \
main_after_prologue: \
;
#endif

View File

@@ -36,7 +36,6 @@ class PathProperties:
'extra_objs_baremetal_bootloader': False, 'extra_objs_baremetal_bootloader': False,
# We should get rid of this if we ever properly implement dependency graphs. # We should get rid of this if we ever properly implement dependency graphs.
'extra_objs_lkmc_common': False, 'extra_objs_lkmc_common': False,
'extra_objs_userland_asm': False,
'interactive': False, 'interactive': False,
# The script takes a perceptible amount of time to run. Possibly an infinite loop. # The script takes a perceptible amount of time to run. Possibly an infinite loop.
'more_than_1s': False, 'more_than_1s': False,
@@ -209,7 +208,7 @@ freestanding_properties = {
'-nostdlib', LF, '-nostdlib', LF,
'-static', LF, '-static', LF,
], ],
'extra_objs_userland_asm': False, 'extra_objs_lkmc_common': False,
} }
# See: https://github.com/cirosantilli/linux-kernel-module-cheat#path-properties # See: https://github.com/cirosantilli/linux-kernel-module-cheat#path-properties
path_properties_tuples = ( path_properties_tuples = (
@@ -284,7 +283,7 @@ path_properties_tuples = (
{ {
'arch': ( 'arch': (
{ {
'extra_objs_userland_asm': True, 'extra_objs_lkmc_common': True,
}, },
{ {
'arm': ( 'arm': (
@@ -311,13 +310,14 @@ path_properties_tuples = (
{ {
'c': ( 'c': (
{ {
'extra_objs_userland_asm': False,
}, },
{ {
'freestanding': freestanding_properties, 'freestanding': freestanding_properties,
}, },
), ),
'freestanding': freestanding_properties, 'freestanding': freestanding_properties,
'lkmc_assert_eq_fail.S': {'exit_status': 1},
'lkmc_assert_memcmp_fail.S': {'exit_status': 1},
'udf.S': { 'udf.S': {
'exit_status': 132, 'exit_status': 132,
'receives_signal': True 'receives_signal': True
@@ -329,13 +329,14 @@ path_properties_tuples = (
{ {
'c': ( 'c': (
{ {
'extra_objs_userland_asm': False,
}, },
{ {
'freestanding': freestanding_properties, 'freestanding': freestanding_properties,
}, },
), ),
'freestanding': freestanding_properties, 'freestanding': freestanding_properties,
'lkmc_assert_eq_fail.S': {'exit_status': 1},
'lkmc_assert_memcmp_fail.S': {'exit_status': 1},
'udf.S': { 'udf.S': {
'exit_status': 132, 'exit_status': 132,
'receives_signal': True 'receives_signal': True
@@ -343,16 +344,11 @@ path_properties_tuples = (
} }
), ),
'fail.S': {'exit_status': 1}, 'fail.S': {'exit_status': 1},
'main.c': {
'extra_objs_userland_asm': False,
'no_executable': True
},
'x86_64': ( 'x86_64': (
{'allowed_archs': {'x86_64'}}, {'allowed_archs': {'x86_64'}},
{ {
'c': ( 'c': (
{ {
'extra_objs_userland_asm': False,
}, },
{ {
'freestanding': freestanding_properties, 'freestanding': freestanding_properties,
@@ -383,11 +379,6 @@ path_properties_tuples = (
), ),
'gcc': gnu_extension_properties, 'gcc': gnu_extension_properties,
'kernel_modules': {**gnu_extension_properties, **{'requires_kernel_modules': True}}, 'kernel_modules': {**gnu_extension_properties, **{'requires_kernel_modules': True}},
'lkmc': (
{'extra_objs_lkmc_common': True},
{
}
),
'libs': ( 'libs': (
{'requires_dynamic_library': True}, {'requires_dynamic_library': True},
{ {

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov x0, 1 mov x0, 1
add x1, x0, 2 add x1, x0, 2
LKMC_ASSERT_EQ(x1, 3) LKMC_ASSERT_EQ(x1, =3)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,9 +3,9 @@
* Add a bunch of integers in one go. * Add a bunch of integers in one go.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.data .data
input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4 input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515 input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515
@@ -22,11 +22,11 @@ LKMC_ENTRY
add v2. ## size, v0. ## size, v1. ## size; \ add v2. ## size, v0. ## size, v1. ## size; \
adr x0, output; \ adr x0, output; \
st1 {v2. ## size}, [x0]; \ st1 {v2. ## size}, [x0]; \
LKMC_ASSERT_MEMCMP(output, expect_ ## size, 0x10) LKMC_ASSERT_MEMCMP(output, expect_ ## size, =0x10)
/* 4x 32-bit */ /* 4x 32-bit */
TEST(4s) TEST(4s)
/* 2x 64-bit */ /* 2x 64-bit */
TEST(2d) TEST(2d)
#undef TEST #undef TEST
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,11 +1,11 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */
#include "common.h" #include <lkmc.h>
.data .data
data_label: data_label:
.word 0x1234678 .word 0x1234678
LKMC_ENTRY LKMC_PROLOGUE
/* This is not possible in v7 because the label is in another section. /* This is not possible in v7 because the label is in another section.
* objdump says that this generates a R_AARCH64_ADR_PRE relocation. * objdump says that this generates a R_AARCH64_ADR_PRE relocation.
* which looks specific to ADR, and therefore makes it more likely * which looks specific to ADR, and therefore makes it more likely
@@ -18,4 +18,4 @@ LKMC_ENTRY
ldr x1, =data_label ldr x1, =data_label
label: label:
LKMC_ASSERT_EQ_REG(x0, x1) LKMC_ASSERT_EQ_REG(x0, x1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
adrp x0, label adrp x0, label
adr x1, label adr x1, label
label: label:
@@ -10,4 +10,4 @@ label:
bic x1, x1, 0xFF bic x1, x1, 0xFF
bic x1, x1, 0xF00 bic x1, x1, 0xF00
LKMC_ASSERT_EQ_REG(x0, x1) LKMC_ASSERT_EQ_REG(x0, x1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,12 +1,12 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-beq-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-beq-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* cbz == 0 */ /* cbz == 0 */
mov x0, 0 mov x0, 0
cbz x0, 1f cbz x0, 1f
LKMC_FAIL LKMC_ASSERT_FAIL
1: 1:
/* cbz != 0 */ /* cbz != 0 */
@@ -14,13 +14,13 @@ LKMC_ENTRY
cbz x0, 1f cbz x0, 1f
b 2f b 2f
1: 1:
LKMC_FAIL LKMC_ASSERT_FAIL
2: 2:
/* cbnz != 0 */ /* cbnz != 0 */
mov x0, 1 mov x0, 1
cbnz x0, 1f cbnz x0, 1f
LKMC_FAIL LKMC_ASSERT_FAIL
1: 1:
/* cbnz == 0 */ /* cbnz == 0 */
@@ -28,6 +28,6 @@ LKMC_ENTRY
cbnz x0, 1f cbnz x0, 1f
b 2f b 2f
1: 1:
LKMC_FAIL LKMC_ASSERT_FAIL
2: 2:
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,11 +1,11 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bfi-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bfi-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr x0, =0x1122334455667788 ldr x0, =0x1122334455667788
ldr x1, =0xFFFFFFFFFFFFFFFF ldr x1, =0xFFFFFFFFFFFFFFFF
bfi x1, x0, 16, 32 bfi x1, x0, 16, 32
LKMC_ASSERT_EQ(x1, 0xFFFF55667788FFFF) LKMC_ASSERT_EQ(x1, =0xFFFF55667788FFFF)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,19 +1,19 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-cbz-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-cbz-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Branch. */ /* Branch. */
mov x0, 0x0 mov x0, 0x0
cbz x0, ok cbz x0, ok
LKMC_FAIL LKMC_ASSERT_FAIL
ok: ok:
/* Don't branch. */ /* Don't branch. */
mov x0, 0x1 mov x0, 0x1
cbz x0, ko cbz x0, ko
LKMC_EXIT LKMC_EPILOGUE
ko: ko:
LKMC_FAIL LKMC_ASSERT_FAIL

View File

@@ -1,7 +1,7 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
# mycomment # mycomment
/* ARMv8 has // instead of @ as for comments. */ /* ARMv8 has // instead of @ as for comments. */
@@ -14,4 +14,4 @@ LKMC_ENTRY
@ mycomment @ mycomment
nop @ mycomment nop @ mycomment
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,83 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library */
#ifndef COMMON_ARCH_H
#define COMMON_ARCH_H
#define LKMC_ASSERT_EQ(reg, const) \
mov x0, reg; \
ldr x1, =const; \
LKMC_ASSERT_EQ_DO(64); \
;
#define LKMC_ASSERT_EQ_DO(bits) \
bl lkmc_assert_eq_ ## bits; \
cmp x0, 0; \
LKMC_ASSERT(beq); \
;
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
str reg2, [sp, -16]!; \
mov x0, reg1; \
ldr x1, [sp], 16; \
LKMC_ASSERT_EQ_DO(64); \
;
#define LKMC_ASSERT_EQ_REG_32(reg1, reg2) \
str reg2, [sp, -4]!; \
mov w0, reg1; \
ldr w1, [sp], 4; \
LKMC_ASSERT_EQ_DO(32); \
;
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
adr x0, label1; \
adr x1, label2; \
ldr x2, =const_size; \
bl lkmc_assert_memcmp; \
cmp x0, 0; \
LKMC_ASSERT(beq); \
;
#define LKMC_ENTRY \
.text; \
.global asm_main; \
asm_main: \
sub sp, sp, 0xA0; \
stp x29, x30, [sp]; \
stp x27, x28, [sp, 0x10]; \
stp x25, x26, [sp, 0x20]; \
stp x23, x24, [sp, 0x30]; \
stp x21, x22, [sp, 0x40]; \
stp x19, x20, [sp, 0x50]; \
stp x6, x7, [sp, 0x60]; \
stp x4, x5, [sp, 0x70]; \
stp x2, x3, [sp, 0x80]; \
stp x0, x1, [sp, 0x90]; \
asm_main_after_prologue: \
;
#define LKMC_EXIT \
mov w0, 0; \
mov w1, 0; \
b pass; \
fail: \
ldr x1, [sp, 0x90]; \
str w0, [x1]; \
mov w0, 1; \
pass: \
ldp x19, x20, [sp, 0x50]; \
ldp x21, x22, [sp, 0x40]; \
ldp x23, x24, [sp, 0x30]; \
ldp x25, x26, [sp, 0x20]; \
ldp x27, x28, [sp, 0x10]; \
ldp x29, x30, [sp]; \
add sp, sp, 0xA0; \
ret; \
;
#define LKMC_FAIL \
ldr w0, =__LINE__; \
b fail; \
;
#endif

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-cset-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-cset-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Test values. */ /* Test values. */
mov x19, 0 mov x19, 0
mov x20, 1 mov x20, 1
@@ -10,19 +10,19 @@ LKMC_ENTRY
/* eq is true, set x21 = 1. */ /* eq is true, set x21 = 1. */
cmp x19, x19 cmp x19, x19
cset x21, eq cset x21, eq
LKMC_ASSERT_EQ(x21, 1) LKMC_ASSERT_EQ(x21, =1)
/* eq is false, set x21 = 0. */ /* eq is false, set x21 = 0. */
cmp x19, x20 cmp x19, x20
cset x21, eq cset x21, eq
LKMC_ASSERT_EQ(x21, 0) LKMC_ASSERT_EQ(x21, =0)
/* Same for ne. */ /* Same for ne. */
cmp x19, x19 cmp x19, x19
cset x21, ne cset x21, ne
LKMC_ASSERT_EQ(x21, 0) LKMC_ASSERT_EQ(x21, =0)
cmp x19, x20 cmp x19, x20
cset x21, ne cset x21, ne
LKMC_ASSERT_EQ(x21, 1) LKMC_ASSERT_EQ(x21, =1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#advanced-simd-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#advanced-simd-instructions */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 1.5 + 2.5 == 4.0 /* 1.5 + 2.5 == 4.0
* using 64-bit double immediates. * using 64-bit double immediates.
*/ */
@@ -57,4 +57,4 @@ my_double_sum_expect:
#if 0 #if 0
fmov d0, 1.23456798 fmov d0, 1.23456798
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,9 +3,9 @@
* Add a bunch of floating point numbers in one go. * Add a bunch of floating point numbers in one go.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.data .data
input0_4s: .float 1.5, 2.5, 3.5, 4.5 input0_4s: .float 1.5, 2.5, 3.5, 4.5
input1_4s: .float 5.5, 6.5, 7.5, 8.5 input1_4s: .float 5.5, 6.5, 7.5, 8.5
@@ -24,11 +24,11 @@ LKMC_ENTRY
fadd v2. ## size, v0. ## size, v1. ## size; \ fadd v2. ## size, v0. ## size, v1. ## size; \
adr x0, output; \ adr x0, output; \
st1 {v2. ## size}, [x0]; \ st1 {v2. ## size}, [x0]; \
LKMC_ASSERT_MEMCMP(output, expect_ ## size, 0x10) LKMC_ASSERT_MEMCMP(output, expect_ ## size, =0x10)
/* 4x 32-bit */ /* 4x 32-bit */
TEST(4s) TEST(4s)
/* 2x 64-bit */ /* 2x 64-bit */
TEST(2d) TEST(2d)
#undef TEST #undef TEST
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,13 +1,13 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
#define ASSERT_DIFF(label1, label2, result) \ #define ASSERT_DIFF(label1, label2, result) \
adr x0, label1; \ adr x0, label1; \
adr x1, label2; \ adr x1, label2; \
sub x0, x1, x0; \ sub x0, x1, x0; \
LKMC_ASSERT_EQ(x0, result) LKMC_ASSERT_EQ(x0, =result)
ASSERT_DIFF(mybyte, myword, 1) ASSERT_DIFF(mybyte, myword, 1)
ASSERT_DIFF(myword, mylong, 4) ASSERT_DIFF(myword, mylong, 4)
@@ -15,7 +15,7 @@ LKMC_ENTRY
ASSERT_DIFF(myquad, myocta, 8) ASSERT_DIFF(myquad, myocta, 8)
ASSERT_DIFF(myocta, theend, 16) ASSERT_DIFF(myocta, theend, 16)
#undef ASSERT_DIF #undef ASSERT_DIF
LKMC_EXIT LKMC_EPILOGUE
mybyte: mybyte:
.byte 0x12 .byte 0x12
myword: myword:

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-immediates */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-immediates */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov x0, 1 mov x0, 1
mov x0, 0x1 mov x0, 0x1
mov x0, 1 mov x0, 1
mov x0, 0x1 mov x0, 0x1
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ld2-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ld2-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.data .data
u32_interleave: .word \ u32_interleave: .word \
0x11111111, 0x55555555, \ 0x11111111, 0x55555555, \
@@ -22,5 +22,5 @@ LKMC_ENTRY
add v2.4s, v0.4s, v1.4s add v2.4s, v0.4s, v1.4s
adr x0, u32_interleave_sum adr x0, u32_interleave_sum
st1 {v2.4s}, [x0] st1 {v2.4s}, [x0]
LKMC_ASSERT_MEMCMP(u32_interleave_sum, u32_interleave_sum_expect, 0x10) LKMC_ASSERT_MEMCMP(u32_interleave_sum, u32_interleave_sum_expect, =0x10)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -0,0 +1,35 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include <lkmc.h>
LKMC_PROLOGUE
ldr x19, =0x123456789ABCDEF0
ldr x20, =0x123456789ABCDEF0
ldr x21, =0x000000009ABCDEF0
/* Passing examples. */
/* Register immediate. */
LKMC_ASSERT_EQ(x19, =0x123456789ABCDEF0)
#if 0
/* Syntax not supported. */
LKMC_ASSERT_EQ(=0x123456789ABCDEF0, x19)
#endif
/* Register register. */
LKMC_ASSERT_EQ_REG(x19, x20)
LKMC_ASSERT_EQ_REG(x20, x19)
LKMC_ASSERT_EQ_REG_32(w19, w21)
LKMC_ASSERT_EQ_REG_32(w21, w19)
/* Register memory. */
LKMC_ASSERT_EQ(x19, myvar)
#if 0
/* Syntax not supported. */
LKMC_ASSERT_EQ(myvar, x19)
#endif
/* Now let's fail. */
LKMC_ASSERT_EQ(x19, =0x123456789ABCDEF1)
LKMC_EPILOGUE
myvar: .quad 0x123456789ABCDEF0

View File

@@ -0,0 +1,15 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include <lkmc.h>
LKMC_PROLOGUE
/* Pass */
LKMC_ASSERT_MEMCMP(var0, var1, =0x10)
LKMC_ASSERT_MEMCMP(var0, var1, size)
/* Fail */
LKMC_ASSERT_MEMCMP(var0, var2, =0x10)
LKMC_EPILOGUE
var0: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var1: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var2: .long 0x11111111, 0x22222223, 0x23333333, 0x44444444
size: .quad 0x10

View File

@@ -1,13 +1,13 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-movk-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-movk-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
movk x0, 0x4444, lsl 0 movk x0, 0x4444, lsl 0
movk x0, 0x3333, lsl 16 movk x0, 0x3333, lsl 16
movk x0, 0x2222, lsl 32 movk x0, 0x2222, lsl 32
movk x0, 0x1111, lsl 48 movk x0, 0x1111, lsl 48
LKMC_ASSERT_EQ(x0, 0x1111222233334444) LKMC_ASSERT_EQ(x0, =0x1111222233334444)
/* Set a label (addresses are 48-bit) with immediates: /* Set a label (addresses are 48-bit) with immediates:
* *
@@ -23,4 +23,4 @@ LKMC_ENTRY
adr x1, label adr x1, label
label: label:
LKMC_ASSERT_EQ_REG(x0, x1) LKMC_ASSERT_EQ_REG(x0, x1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-movn-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-movn-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr x0, =0x123456789ABCDEF0 ldr x0, =0x123456789ABCDEF0
movn x0, 0x8888, lsl 16 movn x0, 0x8888, lsl 16
LKMC_ASSERT_EQ(x0, 0xFFFFFFFF7777FFFF) LKMC_ASSERT_EQ(x0, =0xFFFFFFFF7777FFFF)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
#if 0 #if 0
/* Unlike v7, we can't use PC like any other register in ARMv8, /* Unlike v7, we can't use PC like any other register in ARMv8,
* since it is not a general purpose register anymore. * since it is not a general purpose register anymore.
@@ -16,7 +16,7 @@ LKMC_ENTRY
* exception return. * exception return.
*/ */
ldr pc, =10f ldr pc, =10f
LKMC_FAIL LKMC_ASSERT_FAIL
10: 10:
#endif #endif
#if 0 #if 0
@@ -32,7 +32,7 @@ LKMC_ENTRY
pc_relative_ldr: pc_relative_ldr:
.quad 0x123456789ABCDEF0 .quad 0x123456789ABCDEF0
1: 1:
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0) LKMC_ASSERT_EQ(x0, =0x123456789ABCDEF0)
/* Just for fun, we can also use relative numbers instead of labels. /* Just for fun, we can also use relative numbers instead of labels.
* https://reverseengineering.stackexchange.com/questions/17666/how-does-the-ldr-instruction-work-on-arm/20567#20567 * https://reverseengineering.stackexchange.com/questions/17666/how-does-the-ldr-instruction-work-on-arm/20567#20567
@@ -41,14 +41,14 @@ pc_relative_ldr:
b 1f b 1f
.quad 0x123456789ABCDEF0 .quad 0x123456789ABCDEF0
1: 1:
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0) LKMC_ASSERT_EQ(x0, =0x123456789ABCDEF0)
/* Analogous for b with PC. */ /* Analogous for b with PC. */
mov x0, 0 mov x0, 0
/* Jumps over mov to LKMC_ASSERT_EQ. */ /* Jumps over mov to LKMC_ASSERT_EQ. */
b 8 b 8
mov x0, 1 mov x0, 1
LKMC_ASSERT_EQ(x0, 0) LKMC_ASSERT_EQ(x0, =0)
/* Trying to use the old "LDR (immediate)" PC-relative /* Trying to use the old "LDR (immediate)" PC-relative
* syntax does not work. * syntax does not work.
@@ -66,13 +66,13 @@ pc_relative_ldr:
/* You just have to use adr + "STR (register)". */ /* You just have to use adr + "STR (register)". */
ldr x0, pc_relative_str ldr x0, pc_relative_str
LKMC_ASSERT_EQ(x0, 0x0) LKMC_ASSERT_EQ(x0, =0x0)
adr x1, pc_relative_str adr x1, pc_relative_str
ldr x0, pc_relative_ldr ldr x0, pc_relative_ldr
str x0, [x1] str x0, [x1]
ldr x0, pc_relative_str ldr x0, pc_relative_str
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0) LKMC_ASSERT_EQ(x0, =0x123456789ABCDEF0)
LKMC_EXIT LKMC_EPILOGUE
.data .data
pc_relative_str: pc_relative_str:
.quad 0x0000000000000000 .quad 0x0000000000000000

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 31 64-bit eXtended general purpose registers. */ /* 31 64-bit eXtended general purpose registers. */
mov x0, 0 mov x0, 0
@@ -43,5 +43,5 @@ LKMC_ENTRY
ldr x0, =0x1111222233334444 ldr x0, =0x1111222233334444
ldr x1, =0x5555666677778888 ldr x1, =0x5555666677778888
mov w0, w1 mov w0, w1
LKMC_ASSERT_EQ(x0, 0x0000000077778888) LKMC_ASSERT_EQ(x0, =0x0000000077778888)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,16 +1,16 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-ret-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-ret-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov x19, 1 mov x19, 1
bl inc bl inc
LKMC_ASSERT_EQ(x19, 2) LKMC_ASSERT_EQ(x19, =2)
bl inc2 bl inc2
LKMC_ASSERT_EQ(x19, 3) LKMC_ASSERT_EQ(x19, =3)
bl inc3 bl inc3
LKMC_ASSERT_EQ(x19, 4) LKMC_ASSERT_EQ(x19, =4)
LKMC_EXIT LKMC_EPILOGUE
/* void inc(uint64_t *i) { (*i)++ } */ /* void inc(uint64_t *i) { (*i)++ } */
inc: inc:

View File

@@ -1,13 +1,13 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-str-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-str-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr x0, myvar ldr x0, myvar
LKMC_ASSERT_EQ(x0, 0x12346789ABCDEF0) LKMC_ASSERT_EQ(x0, =0x12346789ABCDEF0)
#if 0 #if 0
/* Error: invalid addressing mode at operand 2 -- `str x0,myvar' */ /* Error: invalid addressing mode at operand 2 -- `str x0,myvar' */
str x0, myvar str x0, myvar
#endif #endif
LKMC_EXIT LKMC_EPILOGUE
myvar: .quad 0x12346789ABCDEF0 myvar: .quad 0x12346789ABCDEF0

View File

@@ -1,17 +1,17 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ubfm-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ubfm-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr x19, =0x1122334455667788 ldr x19, =0x1122334455667788
// lsr alias: imms == 63 // lsr alias: imms == 63
ldr x20, =0xFFFFFFFFFFFFFFFF ldr x20, =0xFFFFFFFFFFFFFFFF
ubfm x20, x19, 16, 63 ubfm x20, x19, 16, 63
LKMC_ASSERT_EQ(x20, 0x0000112233445566) LKMC_ASSERT_EQ(x20, =0x0000112233445566)
ldr x20, =0xFFFFFFFFFFFFFFFF ldr x20, =0xFFFFFFFFFFFFFFFF
ubfm x20, x19, 32, 63 ubfm x20, x19, 32, 63
LKMC_ASSERT_EQ(x20, 0x0000000011223344) LKMC_ASSERT_EQ(x20, =0x0000000011223344)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,15 +1,15 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ubfx-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ubfx-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr x19, =0x1122334455667788 ldr x19, =0x1122334455667788
ldr x20, =0xFFFFFFFFFFFFFFFF ldr x20, =0xFFFFFFFFFFFFFFFF
ubfx x20, x19, 8, 16 ubfx x20, x19, 8, 16
LKMC_ASSERT_EQ(x20, 0x0000000000006677) LKMC_ASSERT_EQ(x20, =0x0000000000006677)
ldr x20, =0xFFFFFFFFFFFFFFFF ldr x20, =0xFFFFFFFFFFFFFFFF
ubfx x20, x19, 8, 32 ubfx x20, x19, 8, 32
LKMC_ASSERT_EQ(x20, 0x0000000044556677) LKMC_ASSERT_EQ(x20, =0x0000000044556677)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,10 +1,10 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-udf-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-udf-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.long 0 .long 0
#if 0 #if 0
udf 0 udf 0
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-x31-register */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#armv8-aarch64-x31-register */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* ERROR: can never use the name x31. */ /* ERROR: can never use the name x31. */
#if 0 #if 0
mov x31, 31 mov x31, 31
@@ -11,12 +11,12 @@ LKMC_ENTRY
/* mov (register) is an alias for ORR, which accepts xzr. */ /* mov (register) is an alias for ORR, which accepts xzr. */
mov x19, 1 mov x19, 1
mov x19, xzr mov x19, xzr
LKMC_ASSERT_EQ(x19, 0) LKMC_ASSERT_EQ(x19, =0)
/* Same encoding as the mov version. */ /* Same encoding as the mov version. */
mov x19, 1 mov x19, 1
orr x19, xzr, xzr orr x19, xzr, xzr
LKMC_ASSERT_EQ(x19, 0) LKMC_ASSERT_EQ(x19, =0)
/* So, orr, which is not an alias, can only take xzr, not sp. */ /* So, orr, which is not an alias, can only take xzr, not sp. */
#if 0 #if 0
@@ -26,7 +26,7 @@ LKMC_ENTRY
/* Zero register discards result if written to. */ /* Zero register discards result if written to. */
mov x19, 1 mov x19, 1
orr xzr, x19, x19 orr xzr, x19, x19
LKMC_ASSERT_EQ(xzr, 0) LKMC_ASSERT_EQ(xzr, =0)
/* MOV (to/from SP) is an alias for ADD (immediate). */ /* MOV (to/from SP) is an alias for ADD (immediate). */
mov x19, sp mov x19, sp
@@ -36,7 +36,7 @@ LKMC_ENTRY
/* Exact same encoding as above. */ /* Exact same encoding as above. */
add x20, sp, 0 add x20, sp, 0
mov sp, x19 mov sp, x19
LKMC_ASSERT_EQ(x20, 1) LKMC_ASSERT_EQ(x20, =1)
/* So, ADD (immediate), which is not an alias, can only take sp, not xzr. */ /* So, ADD (immediate), which is not an alias, can only take sp, not xzr. */
#if 0 #if 0
@@ -48,4 +48,4 @@ LKMC_ENTRY
* does not say anything about SP, and so does accept xzr just fine. * does not say anything about SP, and so does accept xzr just fine.
*/ */
add xzr, xzr, xzr add xzr, xzr, xzr
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-data-processing-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-data-processing-instructions */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Immediate encoding. /* Immediate encoding.
* *
@@ -11,7 +11,7 @@ LKMC_ENTRY
mov r0, 1 mov r0, 1
/* r1 = r0 + 2 */ /* r1 = r0 + 2 */
add r1, r0, 2 add r1, r0, 2
LKMC_ASSERT_EQ(r1, 3) LKMC_ASSERT_EQ(r1, =3)
/* If src == dest, we can omit one of them. /* If src == dest, we can omit one of them.
* *
@@ -19,12 +19,12 @@ LKMC_ENTRY
*/ */
mov r0, 1 mov r0, 1
add r0, 2 add r0, 2
LKMC_ASSERT_EQ(r0, 3) LKMC_ASSERT_EQ(r0, =3)
/* Same as above but explicit. */ /* Same as above but explicit. */
mov r0, 1 mov r0, 1
add r0, r0, 2 add r0, r0, 2
LKMC_ASSERT_EQ(r0, 3) LKMC_ASSERT_EQ(r0, =3)
#if 0 #if 0
/* But we cannot omit the register if there is a shift when using .syntx unified: /* But we cannot omit the register if there is a shift when using .syntx unified:
@@ -44,7 +44,7 @@ LKMC_ENTRY
mov r0, 1 mov r0, 1
mov r1, 2 mov r1, 2
add r2, r0, r1 add r2, r0, r1
LKMC_ASSERT_EQ(r2, 3) LKMC_ASSERT_EQ(r2, =3)
/* Register encoding, omit implicit register. /* Register encoding, omit implicit register.
* *
@@ -53,6 +53,6 @@ LKMC_ENTRY
mov r0, 1 mov r0, 1
mov r1, 2 mov r1, 2
add r1, r0 add r1, r0
LKMC_ASSERT_EQ(r1, 3) LKMC_ASSERT_EQ(r1, =3)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,37 +1,37 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-addressing-modes */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-addressing-modes */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Offset mode with immediate. Add 4 to the address register, /* Offset mode with immediate. Add 4 to the address register,
* which ends up * reading myvar6 instead of myvar. * which ends up * reading myvar6 instead of myvar.
*/ */
adr r4, myvar adr r4, myvar
ldr r5, [r4, 4] ldr r5, [r4, 4]
LKMC_ASSERT_EQ(r5, 0x9ABCDEF0) LKMC_ASSERT_EQ(r5, =0x9ABCDEF0)
/* r4 was not modified. */ /* r4 was not modified. */
LKMC_ASSERT_EQ(r4, myvar) LKMC_ASSERT_EQ(r4, =myvar)
/* Pre-indexed mode: modify register, then use it. */ /* Pre-indexed mode: modify register, then use it. */
adr r4, myvar adr r4, myvar
ldr r5, [r4, 4]! ldr r5, [r4, 4]!
LKMC_ASSERT_EQ(r5, 0x9ABCDEF0) LKMC_ASSERT_EQ(r5, =0x9ABCDEF0)
/* r4 was modified. */ /* r4 was modified. */
LKMC_ASSERT_EQ(r4, myvar6) LKMC_ASSERT_EQ(r4, =myvar6)
/* Post-indexed mode: use register, then modify it. */ /* Post-indexed mode: use register, then modify it. */
adr r4, myvar adr r4, myvar
ldr r5, [r4], 4 ldr r5, [r4], 4
LKMC_ASSERT_EQ(r5, 0x12345678) LKMC_ASSERT_EQ(r5, =0x12345678)
/* r4 was modified. */ /* r4 was modified. */
LKMC_ASSERT_EQ(r4, myvar6) LKMC_ASSERT_EQ(r4, =myvar6)
/* Offset in register. */ /* Offset in register. */
adr r4, myvar adr r4, myvar
mov r5, 4 mov r5, 4
ldr r6, [r4, r5] ldr r6, [r4, r5]
LKMC_ASSERT_EQ(r6, 0x9ABCDEF0) LKMC_ASSERT_EQ(r6, =0x9ABCDEF0)
/* Offset in shifted register: /* Offset in shifted register:
* r6 = * r6 =
@@ -42,9 +42,9 @@ LKMC_ENTRY
adr r4, myvar adr r4, myvar
mov r5, 2 mov r5, 2
ldr r6, [r4, r5, lsl 1] ldr r6, [r4, r5, lsl 1]
LKMC_ASSERT_EQ(r6, 0x9ABCDEF0) LKMC_ASSERT_EQ(r6, =0x9ABCDEF0)
LKMC_EXIT LKMC_EPILOGUE
myvar: myvar:
.word 0x12345678 .word 0x12345678
myvar6: myvar6:

View File

@@ -1,11 +1,11 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-adr-instruction */
#include "common.h" #include <lkmc.h>
.data .data
data_label: data_label:
.word 0x1234678 .word 0x1234678
LKMC_ENTRY LKMC_PROLOGUE
adr r4, label adr r4, label
/* objdump tells us that this uses the literal pool, /* objdump tells us that this uses the literal pool,
* it does not get converted to adr, which is the better * it does not get converted to adr, which is the better
@@ -30,4 +30,4 @@ label:
*/ */
adr r5, data_label adr r5, data_label
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,27 +1,27 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bitwise-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bitwise-instructions */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 0x00 && 0xFF == 0x00 */ /* 0x00 && 0xFF == 0x00 */
mov r0, 0x00 mov r0, 0x00
and r0, 0xFF and r0, 0xFF
LKMC_ASSERT_EQ(r0, 0x00) LKMC_ASSERT_EQ(r0, =0x00)
/* 0x0F && 0xF0 == 0x00 */ /* 0x0F && 0xF0 == 0x00 */
mov r0, 0x0F mov r0, 0x0F
and r0, 0xF0 and r0, 0xF0
LKMC_ASSERT_EQ(r0, 0x00) LKMC_ASSERT_EQ(r0, =0x00)
/* 0x0F && 0xFF == 0x0F */ /* 0x0F && 0xFF == 0x0F */
mov r0, 0x0F mov r0, 0x0F
and r0, 0xFF and r0, 0xFF
LKMC_ASSERT_EQ(r0, 0x0F) LKMC_ASSERT_EQ(r0, =0x0F)
/* 0xF0 && 0xFF == 0xF0 */ /* 0xF0 && 0xFF == 0xF0 */
mov r0, 0xF0 mov r0, 0xF0
and r0, 0xFF and r0, 0xFF
LKMC_ASSERT_EQ(r0, 0xF0) LKMC_ASSERT_EQ(r0, =0xF0)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-b-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-b-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Jump over the fail. 26-bit PC-relative. */ /* Jump over the fail. 26-bit PC-relative. */
b ok b ok
LKMC_FAIL LKMC_ASSERT_FAIL
ok: ok:
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-beq-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-beq-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Smaller*/ /* Smaller*/
mov r0, 1 mov r0, 1
@@ -25,4 +25,4 @@ LKMC_ENTRY
LKMC_ASSERT(bgt) LKMC_ASSERT(bgt)
LKMC_ASSERT(bne) LKMC_ASSERT(bne)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,10 +1,10 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bfi-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bfi-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr r0, =0x11223344 ldr r0, =0x11223344
ldr r1, =0xFFFFFFFF ldr r1, =0xFFFFFFFF
bfi r1, r0, 8, 16 bfi r1, r0, 8, 16
LKMC_ASSERT_EQ(r1, 0xFF3344FF) LKMC_ASSERT_EQ(r1, =0xFF3344FF)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,10 +1,10 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bic-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bic-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 0x0F & ~0x55 == 0x0F & 0xAA == 0x0A */ /* 0x0F & ~0x55 == 0x0F & 0xAA == 0x0A */
mov r0, 0x0F mov r0, 0x0F
bic r0, 0x55 bic r0, 0x55
LKMC_ASSERT_EQ(r0, 0x0A) LKMC_ASSERT_EQ(r0, =0x0A)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,12 +1,12 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bl-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-bl-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov r0, 1 mov r0, 1
bl inc bl inc
LKMC_ASSERT_EQ(r0, 2) LKMC_ASSERT_EQ(r0, =2)
LKMC_EXIT LKMC_EPILOGUE
/* void inc(int *i) { (*i)++ } */ /* void inc(int *i) { (*i)++ } */
inc: inc:

View File

@@ -1,17 +1,17 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#data-bitwise-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#data-bitwise-instructions */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr r0, =0x7FFFFFFF ldr r0, =0x7FFFFFFF
clz r1, r0 clz r1, r0
LKMC_ASSERT_EQ(r1, 1) LKMC_ASSERT_EQ(r1, =1)
ldr r0, =0x3FFFFFFF ldr r0, =0x3FFFFFFF
clz r1, r0 clz r1, r0
LKMC_ASSERT_EQ(r1, 2) LKMC_ASSERT_EQ(r1, =2)
ldr r0, =0x1FFFFFFF ldr r0, =0x1FFFFFFF
clz r1, r0 clz r1, r0
LKMC_ASSERT_EQ(r1, 3) LKMC_ASSERT_EQ(r1, =3)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,7 +1,7 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
# mycomment # mycomment
@ mycomment @ mycomment
/* # only works at the beginning of the line. /* # only works at the beginning of the line.
@@ -11,4 +11,4 @@ LKMC_ENTRY
nop # mycomment nop # mycomment
#endif #endif
nop @ mycomment nop @ mycomment
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,83 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library */
#ifndef COMMON_ARCH_H
#define COMMON_ARCH_H
.syntax unified
/* Assert that a register equals a constant.
* * reg: the register to check
* * const: the constant to compare to. Only works for literals or labels, not for registers.
* For register / register comparison, use LKMC_ASSERT_EQ_REG.
*/
#define LKMC_ASSERT_EQ(reg, const) \
mov r0, reg; \
ldr r1, =const; \
LKMC_ASSERT_EQ_DO; \
;
#define LKMC_ASSERT_EQ_DO \
bl lkmc_assert_eq_32; \
cmp r0, 0; \
LKMC_ASSERT(beq); \
;
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
str reg2, [sp, -4]!; \
mov r0, reg1; \
ldr r1, [sp], 4; \
LKMC_ASSERT_EQ_DO; \
;
/* Assert that two arrays are the same. */
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
ldr r0, =label1; \
ldr r1, =label2; \
ldr r2, =const_size; \
bl lkmc_assert_memcmp; \
cmp r0, 0; \
LKMC_ASSERT(beq); \
;
/* Store all callee saved registers, and LR in case we make further BL calls.
*
* Also save the input arguments r0-r3 on the stack, so we can access them later on,
* despite those registers being overwritten.
*/
#define LKMC_ENTRY \
.text; \
.global asm_main; \
asm_main: \
stmdb sp!, {r0-r12, lr}; \
asm_main_after_prologue: \
;
/* Meant to be called at the end of LKMC_ENTRY.*
*
* Branching to "fail" makes tests fail with exit status 1.
*
* If LKMC_EXIT is reached, the program ends successfully.
*
* Restore LR and bx jump to it to return from asm_main.
*/
#define LKMC_EXIT \
mov r0, 0; \
mov r1, 0; \
b pass; \
fail: \
ldr r1, [sp]; \
str r0, [r1]; \
mov r0, 1; \
pass: \
add sp, 16; \
ldmia sp!, {r4-r12, lr}; \
bx lr; \
;
/* Always fail. */
#define LKMC_FAIL \
ldr r0, =__LINE__; \
b fail; \
;
#endif

View File

@@ -1,16 +1,18 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-conditional-execution */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-conditional-execution */
#include "common.h" #include <lkmc.h>
LKMC_PROLOGUE
mov r4, 0
mov r5, 1
LKMC_ENTRY
mov r0, 0
mov r1, 1
cmp r0, 1
/* Previous cmp failed, skip this operation. */ /* Previous cmp failed, skip this operation. */
addeq r1, 1 cmp r4, 1
LKMC_ASSERT_EQ(r1, 1) addeq r5, 1
cmp r0, 0 LKMC_ASSERT_EQ(r5, =1)
/* Previous passed, do this operation. */ /* Previous passed, do this operation. */
addeq r1, 1 cmp r4, 0
LKMC_ASSERT_EQ(r1, 2) addeq r5, 1
LKMC_EXIT LKMC_ASSERT_EQ(r5, =2)
LKMC_EPILOGUE

View File

@@ -1,6 +1,6 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */
#include "common.h" #include <lkmc.h>
.data .data
mybyte: mybyte:
@@ -14,12 +14,12 @@ myquad:
myocta: myocta:
.octa 0x123456789ABCDEF0123456789ABCDEF0 .octa 0x123456789ABCDEF0123456789ABCDEF0
theend: theend:
LKMC_ENTRY LKMC_PROLOGUE
#define ASSERT_DIFF(label1, label2, result) \ #define ASSERT_DIFF(label1, label2, result) \
ldr r0, =label1; \ ldr r0, =label1; \
ldr r1, =label2; \ ldr r1, =label2; \
sub r0, r1, r0; \ sub r0, r1, r0; \
LKMC_ASSERT_EQ(r0, result) LKMC_ASSERT_EQ(r0, =result)
ASSERT_DIFF(mybyte, myword, 1) ASSERT_DIFF(mybyte, myword, 1)
ASSERT_DIFF(myword, mylong, 4) ASSERT_DIFF(myword, mylong, 4)
@@ -27,4 +27,4 @@ LKMC_ENTRY
ASSERT_DIFF(myquad, myocta, 8) ASSERT_DIFF(myquad, myocta, 8)
ASSERT_DIFF(myocta, theend, 16) ASSERT_DIFF(myocta, theend, 16)
#undef ASSERT_DIF #undef ASSERT_DIF
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-gnu-instruction-gas-assembler-immediates */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-gnu-instruction-gas-assembler-immediates */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* This is the default. We hack it in common.h however. */ /* This is the default. We hack it in common.h however. */
.syntax divided .syntax divided
/* These fail. */ /* These fail. */
@@ -21,4 +21,4 @@ LKMC_ENTRY
mov r0, 0x1 mov r0, 0x1
mov r0, $1 mov r0, $1
mov r0, $0x1 mov r0, $0x1
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,6 +1,6 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-loop-instruction-over-array */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-loop-instruction-over-array */
#include "common.h" #include <lkmc.h>
#define NELEM 4 #define NELEM 4
#define ELEM_SIZE 4 #define ELEM_SIZE 4
@@ -11,7 +11,7 @@ my_array:
my_array_expect: my_array_expect:
.word 0x11111112, 0x22222223, 0x33333334, 0x44444445 .word 0x11111112, 0x22222223, 0x33333334, 0x44444445
LKMC_ENTRY LKMC_PROLOGUE
/* Increment. */ /* Increment. */
ldr r0, =my_array ldr r0, =my_array
mov r1, NELEM mov r1, NELEM
@@ -23,5 +23,5 @@ increment:
sub r1, 1 sub r1, 1
cmp r1, 0 cmp r1, 0
bne increment bne increment
LKMC_ASSERT_MEMCMP(my_array, my_array_expect, 0x10) LKMC_ASSERT_MEMCMP(my_array, my_array_expect, =0x10)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,6 +1,6 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-loop-instruction-over-array */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-loop-instruction-over-array */
#include "common.h" #include <lkmc.h>
#define NELEM 4 #define NELEM 4
#define ELEM_SIZE 4 #define ELEM_SIZE 4
@@ -11,7 +11,7 @@ my_array_0:
my_array_1: my_array_1:
.word 0x55555555, 0x66666666, 0x77777777, 0x88888888 .word 0x55555555, 0x66666666, 0x77777777, 0x88888888
LKMC_ENTRY LKMC_PROLOGUE
/* Load r5, r6, r7 and r8 starting from the address in r4. Don't change r4 */ /* Load r5, r6, r7 and r8 starting from the address in r4. Don't change r4 */
ldr r4, =my_array_0 ldr r4, =my_array_0
@@ -20,11 +20,11 @@ LKMC_ENTRY
ldr r7, =0 ldr r7, =0
ldr r8, =0 ldr r8, =0
ldmia r4, {r5-r8} ldmia r4, {r5-r8}
LKMC_ASSERT_EQ(r4, my_array_0) LKMC_ASSERT_EQ(r4, =my_array_0)
LKMC_ASSERT_EQ(r5, 0x11111111) LKMC_ASSERT_EQ(r5, =0x11111111)
LKMC_ASSERT_EQ(r6, 0x22222222) LKMC_ASSERT_EQ(r6, =0x22222222)
LKMC_ASSERT_EQ(r7, 0x33333333) LKMC_ASSERT_EQ(r7, =0x33333333)
LKMC_ASSERT_EQ(r8, 0x44444444) LKMC_ASSERT_EQ(r8, =0x44444444)
/* Swapping the order of r5 and r6 on the mnemonic makes no difference to load order. /* Swapping the order of r5 and r6 on the mnemonic makes no difference to load order.
* *
@@ -38,8 +38,8 @@ LKMC_ENTRY
ldr r5, =0 ldr r5, =0
ldr r6, =0 ldr r6, =0
ldmia r4, {r6,r5} ldmia r4, {r6,r5}
LKMC_ASSERT_EQ(r5, 0x11111111) LKMC_ASSERT_EQ(r5, =0x11111111)
LKMC_ASSERT_EQ(r6, 0x22222222) LKMC_ASSERT_EQ(r6, =0x22222222)
#endif #endif
/* Modify the array */ /* Modify the array */
@@ -51,11 +51,11 @@ LKMC_ENTRY
stmdb r4, {r5-r8} stmdb r4, {r5-r8}
/* Verify that my_array_0 changed and is equal to my_array_1. */ /* Verify that my_array_0 changed and is equal to my_array_1. */
LKMC_ASSERT_MEMCMP(my_array_0, my_array_1, 0x10) LKMC_ASSERT_MEMCMP(my_array_0, my_array_1, =0x10)
/* Load registers and increment r4. */ /* Load registers and increment r4. */
ldr r4, =my_array_0 ldr r4, =my_array_0
ldmia r4!, {r5-r8} ldmia r4!, {r5-r8}
LKMC_ASSERT_EQ(r4, my_array_1) LKMC_ASSERT_EQ(r4, =my_array_1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldr-instruction-pseudo-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldr-instruction-pseudo-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Mnemonic for a PC relative load: /* Mnemonic for a PC relative load:
* *
@@ -12,13 +12,13 @@ LKMC_ENTRY
* .... * ....
*/ */
ldr r0, myvar ldr r0, myvar
LKMC_ASSERT_EQ(r0, 0x12345678) LKMC_ASSERT_EQ(r0, =0x12345678)
/* Mnemonic PC relative load with an offset. /* Mnemonic PC relative load with an offset.
* Load myvar2 instead of myvar. * Load myvar2 instead of myvar.
*/ */
ldr r0, myvar + 4 ldr r0, myvar + 4
LKMC_ASSERT_EQ(r0, 0x9ABCDEF0) LKMC_ASSERT_EQ(r0, =0x9ABCDEF0)
/* First store the address in r0 using a magic =myvar, which creates /* First store the address in r0 using a magic =myvar, which creates
* a new variable containing the address and PC-relative addresses it * a new variable containing the address and PC-relative addresses it
@@ -33,17 +33,17 @@ LKMC_ENTRY
*/ */
ldr r0, =myvar ldr r0, =myvar
ldr r1, [r0] ldr r1, [r0]
LKMC_ASSERT_EQ(r1, 0x12345678) LKMC_ASSERT_EQ(r1, =0x12345678)
/* More efficiently, use r0 as the address to read, and write to r0 itself. */ /* More efficiently, use r0 as the address to read, and write to r0 itself. */
ldr r0, =myvar ldr r0, =myvar
ldr r0, [r0] ldr r0, [r0]
LKMC_ASSERT_EQ(r0, 0x12345678) LKMC_ASSERT_EQ(r0, =0x12345678)
/* Same as =myvar but store a constant to a register. /* Same as =myvar but store a constant to a register.
* Can also be done with movw and movt. */ * Can also be done with movw and movt. */
ldr r0, =0x11112222 ldr r0, =0x11112222
LKMC_ASSERT_EQ(r0, 0x11112222) LKMC_ASSERT_EQ(r0, =0x11112222)
/* We can also use GAS tolower16 and topper16 and movw and movt /* We can also use GAS tolower16 and topper16 and movw and movt
* to load the address of myvar into r0 with two immediates. * to load the address of myvar into r0 with two immediates.
@@ -56,9 +56,9 @@ LKMC_ENTRY
movw r0, #:lower16:myvar movw r0, #:lower16:myvar
movt r0, #:upper16:myvar movt r0, #:upper16:myvar
ldr r1, [r0] ldr r1, [r0]
LKMC_ASSERT_EQ(r1, 0x12345678) LKMC_ASSERT_EQ(r1, =0x12345678)
LKMC_EXIT LKMC_EPILOGUE
myvar: myvar:
.word 0x12345678 .word 0x12345678
myvar2: myvar2:

View File

@@ -1,12 +1,12 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldrh-instruction-and-ldrb */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldrh-instruction-and-ldrb */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr r0, =myvar ldr r0, =myvar
mov r1, 0x0 mov r1, 0x0
ldrb r1, [r0] ldrb r1, [r0]
LKMC_ASSERT_EQ(r1, 0x00000078) LKMC_ASSERT_EQ(r1, =0x00000078)
LKMC_EXIT LKMC_EPILOGUE
myvar: myvar:
.word 0x12345678 .word 0x12345678

View File

@@ -1,12 +1,12 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldrh-instruction-and-ldrb */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldrh-instruction-and-ldrb */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr r0, =myvar ldr r0, =myvar
mov r1, 0x0 mov r1, 0x0
ldrh r1, [r0] ldrh r1, [r0]
LKMC_ASSERT_EQ(r1, 0x00005678) LKMC_ASSERT_EQ(r1, =0x00005678)
LKMC_EXIT LKMC_EPILOGUE
myvar: myvar:
.word 0x12345678 .word 0x12345678

View File

@@ -1,6 +1,6 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#calling-convention */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-calling-convention */
#include "common.h" #include <lkmc.h>
.data .data
puts_s: puts_s:
@@ -12,7 +12,7 @@ my_array_0:
my_array_1: my_array_1:
.word 0x55555555, 0x66666666, 0x77777777, 0x88888888 .word 0x55555555, 0x66666666, 0x77777777, 0x88888888
LKMC_ENTRY LKMC_PROLOGUE
/* puts("hello world") */ /* puts("hello world") */
/* r0 is first argument. */ /* r0 is first argument. */
ldr r0, =puts_s ldr r0, =puts_s
@@ -49,11 +49,11 @@ LKMC_ENTRY
ldr r1, =my_array_1 ldr r1, =my_array_1
ldr r2, =0x10 ldr r2, =0x10
bl memcmp bl memcmp
LKMC_ASSERT_EQ(r0, 0) LKMC_ASSERT_EQ(r0, =0)
/* exit(0) */ /* exit(0) */
mov r0, 0 mov r0, 0
bl exit bl exit
/* Never reached, just for the fail symbol. */ /* Never reached, just for the fail symbol. */
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -0,0 +1,32 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include <lkmc.h>
LKMC_PROLOGUE
ldr r4, =0x12345678
ldr r5, =0x12345678
/* Passing examples. */
/* Register immediate. */
LKMC_ASSERT_EQ(r4, =0x12345678)
#if 0
/* Syntax not supported. */
LKMC_ASSERT_EQ(=0x12345678, r4)
#endif
/* Register register. */
LKMC_ASSERT_EQ_REG(r4, r5)
LKMC_ASSERT_EQ_REG(r5, r4)
/* Register memory. */
LKMC_ASSERT_EQ(r4, myvar)
#if 0
/* Syntax not supported. */
LKMC_ASSERT_EQ(myvar, r4)
#endif
/* Now let's fail. */
LKMC_ASSERT_EQ(r4, =0x12345679)
LKMC_EPILOGUE
myvar: .quad 0x12345678

View File

@@ -0,0 +1,15 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include <lkmc.h>
LKMC_PROLOGUE
/* Pass */
LKMC_ASSERT_MEMCMP(var0, var1, =0x10)
LKMC_ASSERT_MEMCMP(var0, var1, size)
/* Fail */
LKMC_ASSERT_MEMCMP(var0, var2, =0x10)
LKMC_EPILOGUE
var0: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var1: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var2: .long 0x11111111, 0x22222223, 0x23333333, 0x44444444
size: .long 0x10

View File

@@ -1,19 +1,19 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-mov-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-mov-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Immediate. */ /* Immediate. */
mov r0, 0 mov r0, 0
LKMC_ASSERT_EQ(r0, 0) LKMC_ASSERT_EQ(r0, =0)
mov r0, 1 mov r0, 1
LKMC_ASSERT_EQ(r0, 1) LKMC_ASSERT_EQ(r0, =1)
/* Register. */ /* Register. */
mov r0, 0 mov r0, 0
mov r1, 1 mov r1, 1
mov r1, r0 mov r1, r0
LKMC_ASSERT_EQ(r1, 0) LKMC_ASSERT_EQ(r1, =0)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-movw-and-movt-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-movw-and-movt-instructions */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* movt (top) and movw (TODO what is w) set the higher /* movt (top) and movw (TODO what is w) set the higher
* and lower 16 bits of the register. * and lower 16 bits of the register.
@@ -10,7 +10,7 @@ LKMC_ENTRY
movw r0, 0xFFFF movw r0, 0xFFFF
movt r0, 0x1234 movt r0, 0x1234
add r0, 1 add r0, 1
LKMC_ASSERT_EQ(r0, 0x12350000) LKMC_ASSERT_EQ(r0, =0x12350000)
/* movw also zeroes out the top bits, allowing small 16-bit /* movw also zeroes out the top bits, allowing small 16-bit
* C constants to be assigned in a single instruction. * C constants to be assigned in a single instruction.
@@ -22,6 +22,6 @@ LKMC_ENTRY
*/ */
ldr r0, =0x12345678 ldr r0, =0x12345678
movw r0, 0x1111 movw r0, 0x1111
LKMC_ASSERT_EQ(r0, 0x00001111) LKMC_ASSERT_EQ(r0, =0x00001111)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,13 +3,13 @@
* Multiplication. * Multiplication.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 2 * 3 = 6 */ /* 2 * 3 = 6 */
mov r0, 0 mov r0, 0
mov r1, 2 mov r1, 2
mov r2, 3 mov r2, 3
mul r1, r2 mul r1, r2
LKMC_ASSERT_EQ(r1, 6) LKMC_ASSERT_EQ(r1, =6)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-nop-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-nop-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Disassembles as: /* Disassembles as:
* *
* .... * ....
@@ -29,4 +29,4 @@ LKMC_ENTRY
/* And there are other nops as well? Disassembles as `and`. */ /* And there are other nops as well? Disassembles as `and`. */
and r0, r0, r0 and r0, r0, r0
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldmia-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-ldmia-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Save sp before push. */ /* Save sp before push. */
mov r4, sp mov r4, sp
@@ -19,13 +19,13 @@ LKMC_ENTRY
mov r7, 0 mov r7, 0
mov r8, 0 mov r8, 0
pop {r7, r8} pop {r7, r8}
LKMC_ASSERT_EQ(r7, 1) LKMC_ASSERT_EQ(r7, =1)
LKMC_ASSERT_EQ(r8, 2) LKMC_ASSERT_EQ(r8, =2)
/* Check that stack pointer moved down by 8 bytes /* Check that stack pointer moved down by 8 bytes
* (2 registers x 4 bytes each). * (2 registers x 4 bytes each).
*/ */
sub r4, r5 sub r4, r5
LKMC_ASSERT_EQ(r4, 8) LKMC_ASSERT_EQ(r4, =8)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,10 +3,10 @@
* Reverse bit order. * Reverse bit order.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
ldr r0, =0b00000001001000110100010101100101 ldr r0, =0b00000001001000110100010101100101
rbit r1, r0 rbit r1, r0
LKMC_ASSERT_EQ(r1, 0b10100110101000101100010010000000) LKMC_ASSERT_EQ(r1, =0b10100110101000101100010010000000)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#assembly-registers */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 13 general purpose registers. */ /* 13 general purpose registers. */
mov r0, 0 mov r0, 0
@@ -39,12 +39,12 @@ LKMC_ENTRY
* https://stackoverflow.com/questions/32304646/arm-assembly-branch-to-address-inside-register-or-memory/54145818#54145818 * https://stackoverflow.com/questions/32304646/arm-assembly-branch-to-address-inside-register-or-memory/54145818#54145818
*/ */
ldr pc, =10f ldr pc, =10f
LKMC_FAIL LKMC_ASSERT_FAIL
10: 10:
/* Same with r15, which is the same as pc. */ /* Same with r15, which is the same as pc. */
ldr r15, =10f ldr r15, =10f
LKMC_FAIL LKMC_ASSERT_FAIL
10: 10:
/* Another example with mov reading from pc. */ /* Another example with mov reading from pc. */
@@ -60,10 +60,10 @@ pc_addr:
b 1f b 1f
.word 0x12345678 .word 0x12345678
1: 1:
LKMC_ASSERT_EQ(r0, 0x12345678) LKMC_ASSERT_EQ(r0, =0x12345678)
/* We can also use fp in GNU GAS assembly. */ /* We can also use fp in GNU GAS assembly. */
mov r11, 0 mov r11, 0
mov fp, 1 mov fp, 1
LKMC_ASSERT_EQ(r11, 1) LKMC_ASSERT_EQ(r11, =1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,16 +3,16 @@
* Reverse byte order. * Reverse byte order.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* All bytes in register. */ /* All bytes in register. */
ldr r0, =0x11223344 ldr r0, =0x11223344
rev r1, r0 rev r1, r0
LKMC_ASSERT_EQ(r1, 0x44332211) LKMC_ASSERT_EQ(r1, =0x44332211)
/* Groups of 16-bits. */ /* Groups of 16-bits. */
ldr r0, =0x11223344 ldr r0, =0x11223344
rev16 r1, r0 rev16 r1, r0
LKMC_ASSERT_EQ(r1, 0x22114433) LKMC_ASSERT_EQ(r1, =0x22114433)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-s-suffix */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-s-suffix */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Result is 0, set beq. */ /* Result is 0, set beq. */
movs r0, 0 movs r0, 0
@@ -20,7 +20,7 @@ LKMC_ENTRY
/* movs still moves... */ /* movs still moves... */
mov r0, 0 mov r0, 0
movs r0, 1 movs r0, 1
LKMC_ASSERT_EQ(r0, 1) LKMC_ASSERT_EQ(r0, =1)
/* add: the result is 0. */ /* add: the result is 0. */
mov r0, 1 mov r0, 1
@@ -32,4 +32,4 @@ LKMC_ENTRY
adds r0, 1 adds r0, 1
LKMC_ASSERT(bne) LKMC_ASSERT(bne)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-shift-suffixes */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-shift-suffixes */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* lsr */ /* lsr */
ldr r0, =0xFFF00FFF ldr r0, =0xFFF00FFF
@@ -76,4 +76,4 @@ LKMC_ENTRY
ldr r2, =0x00000120 ldr r2, =0x00000120
LKMC_ASSERT_EQ_REG(r1, r2) LKMC_ASSERT_EQ_REG(r1, r2)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,13 +1,13 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#load-and-store-instructions */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#load-and-store-instructions */
#include "common.h" #include <lkmc.h>
.data; .data;
/* Must be in the .data section, since we want to modify it. */ /* Must be in the .data section, since we want to modify it. */
myvar: myvar:
.word 0x12345678 .word 0x12345678
LKMC_ENTRY LKMC_PROLOGUE
/* Sanity check. */ /* Sanity check. */
ldr r0, =myvar ldr r0, =myvar
ldr r1, [r0] ldr r1, [r0]
@@ -57,4 +57,4 @@ var_in_same_section:
str r1, =myvar str r1, =myvar
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,12 +3,12 @@
* Subtraction. * Subtraction.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 3 - 2 == 1 , register version.*/ /* 3 - 2 == 1 , register version.*/
mov r0, 3 mov r0, 3
mov r1, 2 mov r1, 2
sub r0, r0, r1 sub r0, r0, r1
LKMC_ASSERT_EQ(r0, 1) LKMC_ASSERT_EQ(r0, =1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -7,9 +7,9 @@
.syntax unified .syntax unified
.text .text
.thumb_func .thumb_func
.global asm_main .global main
asm_main: main:
asm_main_after_prologue: main_after_prologue:
/* CBZ: cmp and branch if zero instruction. Equivalent to CMP + BEQ. /* CBZ: cmp and branch if zero instruction. Equivalent to CMP + BEQ.
* TODO create an interesting assertion here. * TODO create an interesting assertion here.

View File

@@ -3,9 +3,9 @@
* Test. Same as ands, but don't store the result, just update flags. * Test. Same as ands, but don't store the result, just update flags.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* 0x0F && 0xF0 == 0x00, so beq. */ /* 0x0F && 0xF0 == 0x00, so beq. */
mov r0, 0x0F mov r0, 0x0F
@@ -17,6 +17,6 @@ LKMC_ENTRY
tst r0, 0x0F tst r0, 0x0F
LKMC_ASSERT(bne) LKMC_ASSERT(bne)
# r0 was not modified. # r0 was not modified.
LKMC_ASSERT_EQ(r0, 0xFF) LKMC_ASSERT_EQ(r0, =0xFF)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,7 +1,7 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-udf-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-udf-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
udf 0 udf 0
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#vfp /* https://github.com/cirosantilli/linux-kernel-module-cheat#vfp
* Adapted from: https://mindplusplus.wordpress.com/2013/06/27/arm-vfp-vector-programming-part-2-examples/ */ * Adapted from: https://mindplusplus.wordpress.com/2013/06/27/arm-vfp-vector-programming-part-2-examples/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Minimal single precision floating point example. /* Minimal single precision floating point example.
* TODO: floating point representation constraints due to 4-byte instruction? * TODO: floating point representation constraints due to 4-byte instruction?
*/ */
@@ -39,7 +39,7 @@ my_float_sum:
vadd.f32 s2, s0, s1 vadd.f32 s2, s0, s1
ldr r0, =my_float_sum ldr r0, =my_float_sum
vstr.f32 s2, [r0] vstr.f32 s2, [r0]
LKMC_ASSERT_MEMCMP(my_float_sum, my_float_sum_expect, 4) LKMC_ASSERT_MEMCMP(my_float_sum, my_float_sum_expect, =4)
#if 0 #if 0
/* We can't do pseudo vldr as for ldr, fails with: /* We can't do pseudo vldr as for ldr, fails with:
@@ -69,4 +69,4 @@ my_float_sum:
vmov s1, s0 vmov s1, s0
vmov r1, s1 vmov r1, s1
LKMC_ASSERT_EQ_REG(r0, r1) LKMC_ASSERT_EQ_REG(r0, r1)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,10 +1,10 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vadd-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vadd-instruction */
#include "common.h" #include <lkmc.h>
.bss .bss
output: .skip 16 output: .skip 16
LKMC_ENTRY LKMC_PROLOGUE
/* Integer. */ /* Integer. */
.data .data
input0_u: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4 input0_u: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
@@ -20,7 +20,7 @@ LKMC_ENTRY
vadd.u ## size q2, q0, q1; \ vadd.u ## size q2, q0, q1; \
ldr r0, =output; \ ldr r0, =output; \
vst1.u ## size {q2}, [r0]; \ vst1.u ## size {q2}, [r0]; \
LKMC_ASSERT_MEMCMP(output, expect_u_ ## size, 0x10) LKMC_ASSERT_MEMCMP(output, expect_u_ ## size, =0x10)
/* vadd.u32 /* vadd.u32
* *
@@ -54,7 +54,7 @@ LKMC_ENTRY
vadd.f ## size q2, q0, q1; \ vadd.f ## size q2, q0, q1; \
ldr r0, =output; \ ldr r0, =output; \
vst1. ## size {q2}, [r0]; \ vst1. ## size {q2}, [r0]; \
LKMC_ASSERT_MEMCMP(output, expect_f_ ## size, 0x10) LKMC_ASSERT_MEMCMP(output, expect_f_ ## size, =0x10)
/* 4x 32-bit. */ /* 4x 32-bit. */
TEST(32) TEST(32)
@@ -68,4 +68,4 @@ LKMC_ENTRY
TEST(64) TEST(64)
#endif #endif
#undef TEST #undef TEST
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvt-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvt-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* SIMD positive. */ /* SIMD positive. */
.data .data
vcvt_positive_0: .float 1.25, 2.5, 3.75, 4.0 vcvt_positive_0: .float 1.25, 2.5, 3.75, 4.0
@@ -15,7 +15,7 @@ LKMC_ENTRY
vcvt.u32.f32 q1, q0 vcvt.u32.f32 q1, q0
ldr r0, =vcvt_positive_result ldr r0, =vcvt_positive_result
vst1.32 {q1}, [r0] vst1.32 {q1}, [r0]
LKMC_ASSERT_MEMCMP(vcvt_positive_result, vcvt_positive_expect, 0x10) LKMC_ASSERT_MEMCMP(vcvt_positive_result, vcvt_positive_expect, =0x10)
/* SIMD negative. */ /* SIMD negative. */
.data .data
@@ -29,7 +29,7 @@ LKMC_ENTRY
vcvt.s32.f32 q1, q0 vcvt.s32.f32 q1, q0
ldr r0, =vcvt_negative_result ldr r0, =vcvt_negative_result
vst1.32 {q1}, [r0] vst1.32 {q1}, [r0]
LKMC_ASSERT_MEMCMP(vcvt_negative_result, vcvt_negative_expect, 0x10) LKMC_ASSERT_MEMCMP(vcvt_negative_result, vcvt_negative_expect, =0x10)
/* Floating point. */ /* Floating point. */
.data .data
@@ -44,7 +44,7 @@ LKMC_ENTRY
vcvt.u32.f32 s0, s0 vcvt.u32.f32 s0, s0
ldr r0, =vcvt_positive_float_result ldr r0, =vcvt_positive_float_result
vst1.32 {d0}, [r0] vst1.32 {d0}, [r0]
LKMC_ASSERT_MEMCMP(vcvt_positive_float_result, vcvt_positive_float_expect, 0x8) LKMC_ASSERT_MEMCMP(vcvt_positive_float_result, vcvt_positive_float_expect, =0x8)
/* Floating point but with immediates. /* Floating point but with immediates.
* *
@@ -85,6 +85,6 @@ LKMC_ENTRY
LKMC_ASSERT_MEMCMP( LKMC_ASSERT_MEMCMP(
vcvt_positive_double_result, vcvt_positive_double_result,
vcvt_positive_double_expect, vcvt_positive_double_expect,
0x4 =0x4
) )
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvta-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvta-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* SIMD positive. */ /* SIMD positive. */
.data .data
vcvta_positive_0: .float 1.25, 2.5, 3.75, 4.0 vcvta_positive_0: .float 1.25, 2.5, 3.75, 4.0
@@ -18,7 +18,7 @@ LKMC_ENTRY
LKMC_ASSERT_MEMCMP( LKMC_ASSERT_MEMCMP(
vcvta_positive_result, vcvta_positive_result,
vcvta_positive_expect, vcvta_positive_expect,
0x10 =0x10
) )
/* SIMD negative. */ /* SIMD negative. */
@@ -36,6 +36,6 @@ LKMC_ENTRY
LKMC_ASSERT_MEMCMP( LKMC_ASSERT_MEMCMP(
vcvta_negative_result, vcvta_negative_result,
vcvta_negative_expect, vcvta_negative_expect,
0x10 =0x10
) )
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvtrr-instruction */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-vcvtrr-instruction */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.data .data
vcvtr_0: .float 1.25, 2.5, 3.75, 4.0 vcvtr_0: .float 1.25, 2.5, 3.75, 4.0
vcvtr_expect_zero: .word 1, 2, 3, 4 vcvtr_expect_zero: .word 1, 2, 3, 4
@@ -24,7 +24,7 @@ LKMC_ENTRY
LKMC_ASSERT_MEMCMP( LKMC_ASSERT_MEMCMP(
vcvtr_result_zero, vcvtr_result_zero,
vcvtr_expect_zero, vcvtr_expect_zero,
0x10 =0x10
) )
#if 0 #if 0
@@ -40,7 +40,7 @@ LKMC_ENTRY
LKMC_ASSERT_MEMCMP( LKMC_ASSERT_MEMCMP(
vcvtr_result_plus_infinity, vcvtr_result_plus_infinity,
vcvtr_expect_plus_infinity, vcvtr_expect_plus_infinity,
0x10 =0x10
) )
#endif #endif
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,32 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library */
#ifndef COMMON_H
#define COMMON_H
/* We define in this header only macros that are the same on all archs. */
/* common_arch.h contains arch specific macros. */
#include "common_arch.h"
.extern \
exit, \
printf, \
puts \
;
/* Assert that the given branch instruction is taken. */
#define LKMC_ASSERT(branch_if_pass) \
branch_if_pass 1f; \
LKMC_FAIL; \
1: \
;
#ifndef LKMC_ASSERT_EQ_REG
/* Assert that a register equals another register. */
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
cmp reg1, reg2; \
LKMC_ASSERT(beq); \
;
#endif
#endif

View File

@@ -2,7 +2,7 @@
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly * https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,9 +1,9 @@
/* See what happens on test failure with LKMC_FAIL. /* See what happens on test failure with LKMC_ASSERT_FAIL.
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly * https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
LKMC_FAIL LKMC_ASSERT_FAIL
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,60 +0,0 @@
/* This is the main entry point for all .S examples.
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
int asm_main(uint32_t *line);
#define ASSERT_EQ_DEFINE(bits) \
int lkmc_assert_eq_ ## bits(uint ## bits ## _t val1, uint ## bits ## _t val2) { \
if (val1 != val2) { \
printf("%s failed\n", __func__); \
printf("val1 0x%" PRIX ## bits "\n", val1); \
printf("val2 0x%" PRIX ## bits "\n", val2); \
return 1; \
} \
return 0; \
}
ASSERT_EQ_DEFINE(32)
ASSERT_EQ_DEFINE(64)
#undef ASSERT_EQ_DEFINE
int lkmc_assert_memcmp(const void *s1, const void *s2, size_t n) {
int ret;
size_t i;
uint8_t *s1b, *s2b;
uint8_t b1, b2;
ret = 0;
s1b = (uint8_t *)s1;
s2b = (uint8_t *)s2;
for (i = 0; i < n; ++i) {
b1 = s1b[i];
b2 = s2b[i];
if (b1 != b2) {
printf(
"%s failed: "
"byte1, byte2, index: "
"0x%02" PRIX8 " 0x%02" PRIX8 " 0x%zX\n",
__func__,
b1,
b2,
i
);
ret = 1;
}
}
return ret;
}
int main(void) {
uint32_t ret, line;
ret = asm_main(&line);
if (ret) {
printf("error: asm_main returned %d at line %d\n", ret, line);
}
return ret;
}

View File

@@ -1,9 +1,9 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov $1, %rax mov $1, %rax
add $2, %rax add $2, %rax
LKMC_ASSERT_EQ(%rax, $3) LKMC_ASSERT_EQ(%rax, $3)
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -3,9 +3,9 @@
* Add a bunch of floating point numbers in one go. * Add a bunch of floating point numbers in one go.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.bss .bss
output: .skip 16 output: .skip 16
.data .data
@@ -28,4 +28,4 @@ LKMC_ENTRY
/* 2x 64-bit */ /* 2x 64-bit */
TEST(d) TEST(d)
#undef TEST #undef TEST
LKMC_EXIT LKMC_EPILOGUE

View File

@@ -1,87 +0,0 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library */
#ifndef COMMON_ARCH_H
#define COMMON_ARCH_H
/* This and other macros may make C function calls, and therefore can destroy
* non-callee saved registers. */
#define LKMC_ASSERT_EQ(general1, general2) \
mov general2, %rdi; \
push %rdi; \
mov general1, %rdi; \
pop %rsi; \
LKMC_ASSERT_EQ_DO(64); \
;
#define LKMC_ASSERT_EQ_DO(bits) \
call lkmc_assert_eq_ ## bits; \
cmp $0, %rax; \
LKMC_ASSERT(je); \
;
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
lea label1(%rip), %rdi; \
lea label2(%rip), %rsi; \
mov const_size, %rdx; \
call lkmc_assert_memcmp; \
cmp $0, %rax; \
LKMC_ASSERT(je); \
;
/* Program entry point.
*
* Return with LKMC_EXIT.
*
* Basically implements an x86_64 prologue:
*
* - save callee saved registers
* x86_64 explained at: https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call/55207335#55207335
* - save register arguments for later usage
*/
#define LKMC_ENTRY \
.text; \
.global asm_main; \
asm_main: \
push %rbp; \
mov %rsp, %rbp; \
push %r15; \
push %r14; \
push %r13; \
push %r12; \
push %rbx; \
push %rdi; \
sub $8, %rsp; \
asm_main_after_prologue: \
;
/* Meant to be called at the end of LKMC_ENTRY.*
*
* Branching to "fail" makes tests fail with exit status 1.
*
* If LKMC_EXIT is reached, the program ends successfully.
*/
#define LKMC_EXIT \
mov $0, %rax; \
jmp pass; \
fail: \
/* -0x30(%rbp) is argument 1 which we pushed at prologue */ \
mov -0x30(%rbp), %rbx; \
movl %eax, (%rbx); \
mov $1, %rax; \
pass: \
add $16, %rsp; \
pop %rbx; \
pop %r12; \
pop %r13; \
pop %r14; \
pop %r15; \
pop %rbp; \
ret; \
;
#define LKMC_FAIL \
mov $__LINE__, %eax; \
jmp fail; \
;
#endif

View File

@@ -1,8 +1,8 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler data sizes */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
#define ASSERT_DIFF(label1, label2, result) \ #define ASSERT_DIFF(label1, label2, result) \
lea label2(%rip), %rax; \ lea label2(%rip), %rax; \
lea label1(%rip), %rbx; \ lea label1(%rip), %rbx; \
@@ -15,7 +15,7 @@ LKMC_ENTRY
ASSERT_DIFF(myquad, myocta, 8) ASSERT_DIFF(myquad, myocta, 8)
ASSERT_DIFF(myocta, theend, 16) ASSERT_DIFF(myocta, theend, 16)
#undef ASSERT_DIF #undef ASSERT_DIF
LKMC_EXIT LKMC_EPILOGUE
mybyte: mybyte:
.byte 0x12 .byte 0x12
myword: myword:

View File

@@ -1,16 +1,26 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
mov $0x123456789ABCDEF0, %r12 mov $0x123456789ABCDEF0, %r12
mov $0x123456789ABCDEF0, %r13 mov $0x123456789ABCDEF0, %r13
/* Passing examples. */
/* Register immediate. */
LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF0) LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF0)
LKMC_ASSERT_EQ(%r12, %r13)
LKMC_ASSERT_EQ(%r12, myvar)
LKMC_ASSERT_EQ($0x123456789ABCDEF0, %r12) LKMC_ASSERT_EQ($0x123456789ABCDEF0, %r12)
/* Register register. */
LKMC_ASSERT_EQ(%r12, %r13)
LKMC_ASSERT_EQ(%r13, %r12) LKMC_ASSERT_EQ(%r13, %r12)
/* Register memory. */
LKMC_ASSERT_EQ(%r12, myvar)
LKMC_ASSERT_EQ(myvar, %r12) LKMC_ASSERT_EQ(myvar, %r12)
/* Now let's fail. */
LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF1) LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF1)
LKMC_EXIT LKMC_EPILOGUE
myvar: .quad 0x123456789ABCDEF0 myvar: .quad 0x123456789ABCDEF0

View File

@@ -1,11 +1,15 @@
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */ /* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
/* Pass */
LKMC_ASSERT_MEMCMP(var0, var1, $0x10) LKMC_ASSERT_MEMCMP(var0, var1, $0x10)
LKMC_ASSERT_MEMCMP(var0, var1, size)
/* Fail */
LKMC_ASSERT_MEMCMP(var0, var2, $0x10) LKMC_ASSERT_MEMCMP(var0, var2, $0x10)
LKMC_EXIT LKMC_EPILOGUE
var0: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444 var0: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var1: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444 var1: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
var2: .long 0x11111111, 0x22222223, 0x23333333, 0x44444444 var2: .long 0x11111111, 0x22222223, 0x23333333, 0x44444444
size: .quad 0x10

View File

@@ -5,9 +5,9 @@
* The different variants basically determine if carries get forwarded or not. * The different variants basically determine if carries get forwarded or not.
*/ */
#include "common.h" #include <lkmc.h>
LKMC_ENTRY LKMC_PROLOGUE
.data .data
input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4 input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515 input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515
@@ -35,4 +35,4 @@ LKMC_ENTRY
/* 2x 16-bit */ /* 2x 16-bit */
TEST(q) TEST(q)
#undef TEST #undef TEST
LKMC_EXIT LKMC_EPILOGUE