mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
userland: scope every header identifier with lkmc_
This commit is contained in:
@@ -26,7 +26,7 @@ class PathProperties:
|
||||
'-fno-pie', LF,
|
||||
'-no-pie', LF,
|
||||
],
|
||||
'cc_flags_after': ['-lm'],
|
||||
'cc_flags_after': ['-lm', LF],
|
||||
'cc_pedantic': True,
|
||||
'cxx_std': default_cxx_std,
|
||||
# Expected program exit status. When signals are raised, this refers
|
||||
|
||||
Submodule submodules/gem5 updated: c4cc3145cd...1bfc29b059
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov x0, 1
|
||||
add x1, x0, 2
|
||||
ASSERT_EQ(x1, 3)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x1, 3)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.data
|
||||
input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
|
||||
input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515
|
||||
@@ -22,11 +22,11 @@ ENTRY
|
||||
add v2. ## size, v0. ## size, v1. ## size; \
|
||||
adr x0, output; \
|
||||
st1 {v2. ## size}, [x0]; \
|
||||
ASSERT_MEMCMP(output, expect_ ## size, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, expect_ ## size, 0x10)
|
||||
|
||||
/* 4x 32-bit */
|
||||
TEST(4s)
|
||||
/* 2x 64-bit */
|
||||
TEST(2d)
|
||||
#undef TEST
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.data
|
||||
data_label:
|
||||
.word 0x1234678
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* This is not possible in v7 because the label is in another section.
|
||||
* objdump says that this generates a R_AARCH64_ADR_PRE relocation.
|
||||
* which looks specific to ADR, and therefore makes it more likely
|
||||
@@ -17,5 +17,5 @@ ENTRY
|
||||
adr x0, data_label
|
||||
ldr x1, =data_label
|
||||
label:
|
||||
ASSERT_EQ_REG(x0, x1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ_REG(x0, x1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
adrp x0, label
|
||||
adr x1, label
|
||||
label:
|
||||
/* Clear the lower 12 bits. */
|
||||
bic x1, x1, 0xFF
|
||||
bic x1, x1, 0xF00
|
||||
ASSERT_EQ_REG(x0, x1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ_REG(x0, x1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* cbz == 0 */
|
||||
mov x0, 0
|
||||
cbz x0, 1f
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
1:
|
||||
|
||||
/* cbz != 0 */
|
||||
@@ -14,13 +14,13 @@ ENTRY
|
||||
cbz x0, 1f
|
||||
b 2f
|
||||
1:
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
2:
|
||||
|
||||
/* cbnz != 0 */
|
||||
mov x0, 1
|
||||
cbnz x0, 1f
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
1:
|
||||
|
||||
/* cbnz == 0 */
|
||||
@@ -28,6 +28,6 @@ ENTRY
|
||||
cbnz x0, 1f
|
||||
b 2f
|
||||
1:
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
2:
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr x0, =0x1122334455667788
|
||||
|
||||
ldr x1, =0xFFFFFFFFFFFFFFFF
|
||||
bfi x1, x0, 16, 32
|
||||
ASSERT_EQ(x1, 0xFFFF55667788FFFF)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x1, 0xFFFF55667788FFFF)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Branch. */
|
||||
mov x0, 0x0
|
||||
cbz x0, ok
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
ok:
|
||||
|
||||
/* Don't branch. */
|
||||
mov x0, 0x1
|
||||
cbz x0, ko
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
ko:
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */
|
||||
|
||||
#include "common.h"
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
# mycomment
|
||||
|
||||
/* ARMv8 has // instead of @ as for comments. */
|
||||
@@ -14,4 +14,4 @@ ENTRY
|
||||
@ mycomment
|
||||
nop @ mycomment
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -3,42 +3,42 @@
|
||||
#ifndef COMMON_ARCH_H
|
||||
#define COMMON_ARCH_H
|
||||
|
||||
#define ASSERT_EQ(reg, const) \
|
||||
#define LKMC_ASSERT_EQ(reg, const) \
|
||||
mov x0, reg; \
|
||||
ldr x1, =const; \
|
||||
ASSERT_EQ_DO(64); \
|
||||
LKMC_ASSERT_EQ_DO(64); \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_DO(bits) \
|
||||
bl assert_eq_ ## bits; \
|
||||
#define LKMC_ASSERT_EQ_DO(bits) \
|
||||
bl lkmc_assert_eq_ ## bits; \
|
||||
cmp x0, 0; \
|
||||
ASSERT(beq); \
|
||||
LKMC_ASSERT(beq); \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
|
||||
str reg2, [sp, -16]!; \
|
||||
mov x0, reg1; \
|
||||
ldr x1, [sp], 16; \
|
||||
ASSERT_EQ_DO(64); \
|
||||
LKMC_ASSERT_EQ_DO(64); \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_REG_32(reg1, reg2) \
|
||||
#define LKMC_ASSERT_EQ_REG_32(reg1, reg2) \
|
||||
str reg2, [sp, -4]!; \
|
||||
mov w0, reg1; \
|
||||
ldr w1, [sp], 4; \
|
||||
ASSERT_EQ_DO(32); \
|
||||
LKMC_ASSERT_EQ_DO(32); \
|
||||
;
|
||||
|
||||
#define ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
adr x0, label1; \
|
||||
adr x1, label2; \
|
||||
ldr x2, =const_size; \
|
||||
bl assert_memcmp; \
|
||||
bl lkmc_assert_memcmp; \
|
||||
cmp x0, 0; \
|
||||
ASSERT(beq); \
|
||||
LKMC_ASSERT(beq); \
|
||||
;
|
||||
|
||||
#define ENTRY \
|
||||
#define LKMC_ENTRY \
|
||||
.text; \
|
||||
.global asm_main; \
|
||||
asm_main: \
|
||||
@@ -56,7 +56,7 @@ asm_main: \
|
||||
asm_main_after_prologue: \
|
||||
;
|
||||
|
||||
#define EXIT \
|
||||
#define LKMC_EXIT \
|
||||
mov w0, 0; \
|
||||
mov w1, 0; \
|
||||
b pass; \
|
||||
@@ -75,7 +75,7 @@ pass: \
|
||||
ret; \
|
||||
;
|
||||
|
||||
#define FAIL \
|
||||
#define LKMC_FAIL \
|
||||
ldr w0, =__LINE__; \
|
||||
b fail; \
|
||||
;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Test values. */
|
||||
mov x19, 0
|
||||
mov x20, 1
|
||||
@@ -10,19 +10,19 @@ ENTRY
|
||||
/* eq is true, set x21 = 1. */
|
||||
cmp x19, x19
|
||||
cset x21, eq
|
||||
ASSERT_EQ(x21, 1)
|
||||
LKMC_ASSERT_EQ(x21, 1)
|
||||
|
||||
/* eq is false, set x21 = 0. */
|
||||
cmp x19, x20
|
||||
cset x21, eq
|
||||
ASSERT_EQ(x21, 0)
|
||||
LKMC_ASSERT_EQ(x21, 0)
|
||||
|
||||
/* Same for ne. */
|
||||
cmp x19, x19
|
||||
cset x21, ne
|
||||
ASSERT_EQ(x21, 0)
|
||||
LKMC_ASSERT_EQ(x21, 0)
|
||||
|
||||
cmp x19, x20
|
||||
cset x21, ne
|
||||
ASSERT_EQ(x21, 1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x21, 1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* 1.5 + 2.5 == 4.0
|
||||
* using 64-bit double immediates.
|
||||
*/
|
||||
@@ -14,7 +14,7 @@ ENTRY
|
||||
* automatically in the main CPSR.
|
||||
*/
|
||||
fcmp d2, d3
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* Now with a memory stored value. */
|
||||
.data
|
||||
@@ -30,7 +30,7 @@ my_double_sum_expect:
|
||||
fadd d2, d0, d1
|
||||
ldr d3, my_double_sum_expect
|
||||
fcmp d2, d3
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* Now in 32-bit. */
|
||||
fmov s0, 1.5
|
||||
@@ -38,7 +38,7 @@ my_double_sum_expect:
|
||||
fadd s2, s0, s1
|
||||
fmov s3, 4.0
|
||||
fcmp s2, s3
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* TODO why? What's the point of q then?
|
||||
* Error: operand mismatch -- `fmov q0,1.5'
|
||||
@@ -57,4 +57,4 @@ my_double_sum_expect:
|
||||
#if 0
|
||||
fmov d0, 1.23456798
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.data
|
||||
input0_4s: .float 1.5, 2.5, 3.5, 4.5
|
||||
input1_4s: .float 5.5, 6.5, 7.5, 8.5
|
||||
@@ -24,11 +24,11 @@ ENTRY
|
||||
fadd v2. ## size, v0. ## size, v1. ## size; \
|
||||
adr x0, output; \
|
||||
st1 {v2. ## size}, [x0]; \
|
||||
ASSERT_MEMCMP(output, expect_ ## size, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, expect_ ## size, 0x10)
|
||||
|
||||
/* 4x 32-bit */
|
||||
TEST(4s)
|
||||
/* 2x 64-bit */
|
||||
TEST(2d)
|
||||
#undef TEST
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
#define ASSERT_DIFF(label1, label2, result) \
|
||||
adr x0, label1; \
|
||||
adr x1, label2; \
|
||||
sub x0, x1, x0; \
|
||||
ASSERT_EQ(x0, result)
|
||||
LKMC_ASSERT_EQ(x0, result)
|
||||
|
||||
ASSERT_DIFF(mybyte, myword, 1)
|
||||
ASSERT_DIFF(myword, mylong, 4)
|
||||
@@ -15,7 +15,7 @@ ENTRY
|
||||
ASSERT_DIFF(myquad, myocta, 8)
|
||||
ASSERT_DIFF(myocta, theend, 16)
|
||||
#undef ASSERT_DIF
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
mybyte:
|
||||
.byte 0x12
|
||||
myword:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-immediates */
|
||||
|
||||
#include "common.h"
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov x0, 1
|
||||
mov x0, 0x1
|
||||
mov x0, 1
|
||||
mov x0, 0x1
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.data
|
||||
u32_interleave: .word \
|
||||
0x11111111, 0x55555555, \
|
||||
@@ -22,5 +22,5 @@ ENTRY
|
||||
add v2.4s, v0.4s, v1.4s
|
||||
adr x0, u32_interleave_sum
|
||||
st1 {v2.4s}, [x0]
|
||||
ASSERT_MEMCMP(u32_interleave_sum, u32_interleave_sum_expect, 0x10)
|
||||
EXIT
|
||||
LKMC_ASSERT_MEMCMP(u32_interleave_sum, u32_interleave_sum_expect, 0x10)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
movk x0, 0x4444, lsl 0
|
||||
movk x0, 0x3333, lsl 16
|
||||
movk x0, 0x2222, lsl 32
|
||||
movk x0, 0x1111, lsl 48
|
||||
ASSERT_EQ(x0, 0x1111222233334444)
|
||||
LKMC_ASSERT_EQ(x0, 0x1111222233334444)
|
||||
|
||||
/* Set a label (addresses are 48-bit) with immediates:
|
||||
*
|
||||
@@ -22,5 +22,5 @@ ENTRY
|
||||
movk x0, :abs_g0_nc:label /* bits 0-15, no overflow check */
|
||||
adr x1, label
|
||||
label:
|
||||
ASSERT_EQ_REG(x0, x1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ_REG(x0, x1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr x0, =0x123456789ABCDEF0
|
||||
movn x0, 0x8888, lsl 16
|
||||
ASSERT_EQ(x0, 0xFFFFFFFF7777FFFF)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x0, 0xFFFFFFFF7777FFFF)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
#if 0
|
||||
/* Unlike v7, we can't use PC like any other register in ARMv8,
|
||||
* since it is not a general purpose register anymore.
|
||||
@@ -16,7 +16,7 @@ ENTRY
|
||||
* exception return.
|
||||
*/
|
||||
ldr pc, =10f
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
10:
|
||||
#endif
|
||||
#if 0
|
||||
@@ -32,7 +32,7 @@ ENTRY
|
||||
pc_relative_ldr:
|
||||
.quad 0x123456789ABCDEF0
|
||||
1:
|
||||
ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
|
||||
/* 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
|
||||
@@ -41,14 +41,14 @@ pc_relative_ldr:
|
||||
b 1f
|
||||
.quad 0x123456789ABCDEF0
|
||||
1:
|
||||
ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
|
||||
/* Analogous for b with PC. */
|
||||
mov x0, 0
|
||||
/* Jumps over mov to ASSERT_EQ. */
|
||||
/* Jumps over mov to LKMC_ASSERT_EQ. */
|
||||
b 8
|
||||
mov x0, 1
|
||||
ASSERT_EQ(x0, 0)
|
||||
LKMC_ASSERT_EQ(x0, 0)
|
||||
|
||||
/* Trying to use the old "LDR (immediate)" PC-relative
|
||||
* syntax does not work.
|
||||
@@ -66,13 +66,13 @@ pc_relative_ldr:
|
||||
|
||||
/* You just have to use adr + "STR (register)". */
|
||||
ldr x0, pc_relative_str
|
||||
ASSERT_EQ(x0, 0x0)
|
||||
LKMC_ASSERT_EQ(x0, 0x0)
|
||||
adr x1, pc_relative_str
|
||||
ldr x0, pc_relative_ldr
|
||||
str x0, [x1]
|
||||
ldr x0, pc_relative_str
|
||||
ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x0, 0x123456789ABCDEF0)
|
||||
LKMC_EXIT
|
||||
.data
|
||||
pc_relative_str:
|
||||
.quad 0x0000000000000000
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* 31 64-bit eXtended general purpose registers. */
|
||||
mov x0, 0
|
||||
@@ -43,5 +43,5 @@ ENTRY
|
||||
ldr x0, =0x1111222233334444
|
||||
ldr x1, =0x5555666677778888
|
||||
mov w0, w1
|
||||
ASSERT_EQ(x0, 0x0000000077778888)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x0, 0x0000000077778888)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov x19, 1
|
||||
bl inc
|
||||
ASSERT_EQ(x19, 2)
|
||||
LKMC_ASSERT_EQ(x19, 2)
|
||||
bl inc2
|
||||
ASSERT_EQ(x19, 3)
|
||||
LKMC_ASSERT_EQ(x19, 3)
|
||||
bl inc3
|
||||
ASSERT_EQ(x19, 4)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x19, 4)
|
||||
LKMC_EXIT
|
||||
|
||||
/* void inc(uint64_t *i) { (*i)++ } */
|
||||
inc:
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr x0, myvar
|
||||
ASSERT_EQ(x0, 0x12346789ABCDEF0)
|
||||
LKMC_ASSERT_EQ(x0, 0x12346789ABCDEF0)
|
||||
#if 0
|
||||
/* Error: invalid addressing mode at operand 2 -- `str x0,myvar' */
|
||||
str x0, myvar
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
myvar: .quad 0x12346789ABCDEF0
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr x19, =0x1122334455667788
|
||||
|
||||
// lsr alias: imms == 63
|
||||
|
||||
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||
ubfm x20, x19, 16, 63
|
||||
ASSERT_EQ(x20, 0x0000112233445566)
|
||||
LKMC_ASSERT_EQ(x20, 0x0000112233445566)
|
||||
|
||||
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||
ubfm x20, x19, 32, 63
|
||||
ASSERT_EQ(x20, 0x0000000011223344)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x20, 0x0000000011223344)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr x19, =0x1122334455667788
|
||||
|
||||
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||
ubfx x20, x19, 8, 16
|
||||
ASSERT_EQ(x20, 0x0000000000006677)
|
||||
LKMC_ASSERT_EQ(x20, 0x0000000000006677)
|
||||
|
||||
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||
ubfx x20, x19, 8, 32
|
||||
ASSERT_EQ(x20, 0x0000000044556677)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(x20, 0x0000000044556677)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.long 0
|
||||
#if 0
|
||||
udf 0
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* ERROR: can never use the name x31. */
|
||||
#if 0
|
||||
mov x31, 31
|
||||
@@ -11,12 +11,12 @@ ENTRY
|
||||
/* mov (register) is an alias for ORR, which accepts xzr. */
|
||||
mov x19, 1
|
||||
mov x19, xzr
|
||||
ASSERT_EQ(x19, 0)
|
||||
LKMC_ASSERT_EQ(x19, 0)
|
||||
|
||||
/* Same encoding as the mov version. */
|
||||
mov x19, 1
|
||||
orr x19, xzr, xzr
|
||||
ASSERT_EQ(x19, 0)
|
||||
LKMC_ASSERT_EQ(x19, 0)
|
||||
|
||||
/* So, orr, which is not an alias, can only take xzr, not sp. */
|
||||
#if 0
|
||||
@@ -26,7 +26,7 @@ ENTRY
|
||||
/* Zero register discards result if written to. */
|
||||
mov x19, 1
|
||||
orr xzr, x19, x19
|
||||
ASSERT_EQ(xzr, 0)
|
||||
LKMC_ASSERT_EQ(xzr, 0)
|
||||
|
||||
/* MOV (to/from SP) is an alias for ADD (immediate). */
|
||||
mov x19, sp
|
||||
@@ -36,7 +36,7 @@ ENTRY
|
||||
/* Exact same encoding as above. */
|
||||
add x20, sp, 0
|
||||
mov sp, x19
|
||||
ASSERT_EQ(x20, 1)
|
||||
LKMC_ASSERT_EQ(x20, 1)
|
||||
|
||||
/* So, ADD (immediate), which is not an alias, can only take sp, not xzr. */
|
||||
#if 0
|
||||
@@ -48,4 +48,4 @@ ENTRY
|
||||
* does not say anything about SP, and so does accept xzr just fine.
|
||||
*/
|
||||
add xzr, xzr, xzr
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Immediate encoding.
|
||||
*
|
||||
@@ -11,7 +11,7 @@ ENTRY
|
||||
mov r0, 1
|
||||
/* r1 = r0 + 2 */
|
||||
add r1, r0, 2
|
||||
ASSERT_EQ(r1, 3)
|
||||
LKMC_ASSERT_EQ(r1, 3)
|
||||
|
||||
/* If src == dest, we can omit one of them.
|
||||
*
|
||||
@@ -19,12 +19,12 @@ ENTRY
|
||||
*/
|
||||
mov r0, 1
|
||||
add r0, 2
|
||||
ASSERT_EQ(r0, 3)
|
||||
LKMC_ASSERT_EQ(r0, 3)
|
||||
|
||||
/* Same as above but explicit. */
|
||||
mov r0, 1
|
||||
add r0, r0, 2
|
||||
ASSERT_EQ(r0, 3)
|
||||
LKMC_ASSERT_EQ(r0, 3)
|
||||
|
||||
#if 0
|
||||
/* But we cannot omit the register if there is a shift when using .syntx unified:
|
||||
@@ -44,7 +44,7 @@ ENTRY
|
||||
mov r0, 1
|
||||
mov r1, 2
|
||||
add r2, r0, r1
|
||||
ASSERT_EQ(r2, 3)
|
||||
LKMC_ASSERT_EQ(r2, 3)
|
||||
|
||||
/* Register encoding, omit implicit register.
|
||||
*
|
||||
@@ -53,6 +53,6 @@ ENTRY
|
||||
mov r0, 1
|
||||
mov r1, 2
|
||||
add r1, r0
|
||||
ASSERT_EQ(r1, 3)
|
||||
LKMC_ASSERT_EQ(r1, 3)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,36 +2,36 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Offset mode with immediate. Add 4 to the address register,
|
||||
* which ends up * reading myvar6 instead of myvar.
|
||||
*/
|
||||
adr r4, myvar
|
||||
ldr r5, [r4, 4]
|
||||
ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||
LKMC_ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||
/* r4 was not modified. */
|
||||
ASSERT_EQ(r4, myvar)
|
||||
LKMC_ASSERT_EQ(r4, myvar)
|
||||
|
||||
/* Pre-indexed mode: modify register, then use it. */
|
||||
adr r4, myvar
|
||||
ldr r5, [r4, 4]!
|
||||
ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||
LKMC_ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||
/* r4 was modified. */
|
||||
ASSERT_EQ(r4, myvar6)
|
||||
LKMC_ASSERT_EQ(r4, myvar6)
|
||||
|
||||
/* Post-indexed mode: use register, then modify it. */
|
||||
adr r4, myvar
|
||||
ldr r5, [r4], 4
|
||||
ASSERT_EQ(r5, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r5, 0x12345678)
|
||||
/* r4 was modified. */
|
||||
ASSERT_EQ(r4, myvar6)
|
||||
LKMC_ASSERT_EQ(r4, myvar6)
|
||||
|
||||
/* Offset in register. */
|
||||
adr r4, myvar
|
||||
mov r5, 4
|
||||
ldr r6, [r4, r5]
|
||||
ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||
LKMC_ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||
|
||||
/* Offset in shifted register:
|
||||
* r6 =
|
||||
@@ -42,9 +42,9 @@ ENTRY
|
||||
adr r4, myvar
|
||||
mov r5, 2
|
||||
ldr r6, [r4, r5, lsl 1]
|
||||
ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||
LKMC_ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
myvar:
|
||||
.word 0x12345678
|
||||
myvar6:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.data
|
||||
data_label:
|
||||
.word 0x1234678
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
adr r4, label
|
||||
/* objdump tells us that this uses the literal pool,
|
||||
* it does not get converted to adr, which is the better
|
||||
@@ -14,8 +14,8 @@ ENTRY
|
||||
ldr r5, =label
|
||||
adrl r6, label
|
||||
label:
|
||||
ASSERT_EQ_REG(r4, r5)
|
||||
ASSERT_EQ_REG(r4, r6)
|
||||
LKMC_ASSERT_EQ_REG(r4, r5)
|
||||
LKMC_ASSERT_EQ_REG(r4, r6)
|
||||
|
||||
#if 0
|
||||
/* Error: symbol .data is in a different section.
|
||||
@@ -30,4 +30,4 @@ label:
|
||||
*/
|
||||
adr r5, data_label
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,26 +2,26 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* 0x00 && 0xFF == 0x00 */
|
||||
mov r0, 0x00
|
||||
and r0, 0xFF
|
||||
ASSERT_EQ(r0, 0x00)
|
||||
LKMC_ASSERT_EQ(r0, 0x00)
|
||||
|
||||
/* 0x0F && 0xF0 == 0x00 */
|
||||
mov r0, 0x0F
|
||||
and r0, 0xF0
|
||||
ASSERT_EQ(r0, 0x00)
|
||||
LKMC_ASSERT_EQ(r0, 0x00)
|
||||
|
||||
/* 0x0F && 0xFF == 0x0F */
|
||||
mov r0, 0x0F
|
||||
and r0, 0xFF
|
||||
ASSERT_EQ(r0, 0x0F)
|
||||
LKMC_ASSERT_EQ(r0, 0x0F)
|
||||
|
||||
/* 0xF0 && 0xFF == 0xF0 */
|
||||
mov r0, 0xF0
|
||||
and r0, 0xFF
|
||||
ASSERT_EQ(r0, 0xF0)
|
||||
LKMC_ASSERT_EQ(r0, 0xF0)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#arm-b-instruction */
|
||||
|
||||
#include "common.h"
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Jump over the fail. 26-bit PC-relative. */
|
||||
b ok
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
ok:
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Smaller*/
|
||||
mov r0, 1
|
||||
cmp r0, 2
|
||||
ASSERT(ble)
|
||||
ASSERT(blt)
|
||||
ASSERT(bne)
|
||||
LKMC_ASSERT(ble)
|
||||
LKMC_ASSERT(blt)
|
||||
LKMC_ASSERT(bne)
|
||||
|
||||
/* Equal. */
|
||||
mov r1, 0
|
||||
cmp r1, 0
|
||||
ASSERT(beq)
|
||||
ASSERT(bge)
|
||||
ASSERT(ble)
|
||||
LKMC_ASSERT(beq)
|
||||
LKMC_ASSERT(bge)
|
||||
LKMC_ASSERT(ble)
|
||||
|
||||
/* Greater. */
|
||||
mov r0, 2
|
||||
cmp r0, 1
|
||||
ASSERT(bge)
|
||||
ASSERT(bgt)
|
||||
ASSERT(bne)
|
||||
LKMC_ASSERT(bge)
|
||||
LKMC_ASSERT(bgt)
|
||||
LKMC_ASSERT(bne)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr r0, =0x11223344
|
||||
ldr r1, =0xFFFFFFFF
|
||||
bfi r1, r0, 8, 16
|
||||
ASSERT_EQ(r1, 0xFF3344FF)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 0xFF3344FF)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* 0x0F & ~0x55 == 0x0F & 0xAA == 0x0A */
|
||||
mov r0, 0x0F
|
||||
bic r0, 0x55
|
||||
ASSERT_EQ(r0, 0x0A)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r0, 0x0A)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov r0, 1
|
||||
bl inc
|
||||
ASSERT_EQ(r0, 2)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r0, 2)
|
||||
LKMC_EXIT
|
||||
|
||||
/* void inc(int *i) { (*i)++ } */
|
||||
inc:
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr r0, =0x7FFFFFFF
|
||||
clz r1, r0
|
||||
ASSERT_EQ(r1, 1)
|
||||
LKMC_ASSERT_EQ(r1, 1)
|
||||
|
||||
ldr r0, =0x3FFFFFFF
|
||||
clz r1, r0
|
||||
ASSERT_EQ(r1, 2)
|
||||
LKMC_ASSERT_EQ(r1, 2)
|
||||
|
||||
ldr r0, =0x1FFFFFFF
|
||||
clz r1, r0
|
||||
ASSERT_EQ(r1, 3)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 3)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#gnu-gas-assembler-comments */
|
||||
|
||||
#include "common.h"
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
# mycomment
|
||||
@ mycomment
|
||||
/* # only works at the beginning of the line.
|
||||
@@ -11,4 +11,4 @@ ENTRY
|
||||
nop # mycomment
|
||||
#endif
|
||||
nop @ mycomment
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -8,35 +8,35 @@
|
||||
/* 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 ASSERT_EQ_REG.
|
||||
* For register / register comparison, use LKMC_ASSERT_EQ_REG.
|
||||
*/
|
||||
#define ASSERT_EQ(reg, const) \
|
||||
#define LKMC_ASSERT_EQ(reg, const) \
|
||||
mov r0, reg; \
|
||||
ldr r1, =const; \
|
||||
ASSERT_EQ_DO; \
|
||||
LKMC_ASSERT_EQ_DO; \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_DO \
|
||||
bl assert_eq_32; \
|
||||
#define LKMC_ASSERT_EQ_DO \
|
||||
bl lkmc_assert_eq_32; \
|
||||
cmp r0, 0; \
|
||||
ASSERT(beq); \
|
||||
LKMC_ASSERT(beq); \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
|
||||
str reg2, [sp, -4]!; \
|
||||
mov r0, reg1; \
|
||||
ldr r1, [sp], 4; \
|
||||
ASSERT_EQ_DO; \
|
||||
LKMC_ASSERT_EQ_DO; \
|
||||
;
|
||||
|
||||
/* Assert that two arrays are the same. */
|
||||
#define ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
ldr r0, =label1; \
|
||||
ldr r1, =label2; \
|
||||
ldr r2, =const_size; \
|
||||
bl assert_memcmp; \
|
||||
bl lkmc_assert_memcmp; \
|
||||
cmp r0, 0; \
|
||||
ASSERT(beq); \
|
||||
LKMC_ASSERT(beq); \
|
||||
;
|
||||
|
||||
/* Store all callee saved registers, and LR in case we make further BL calls.
|
||||
@@ -44,7 +44,7 @@
|
||||
* Also save the input arguments r0-r3 on the stack, so we can access them later on,
|
||||
* despite those registers being overwritten.
|
||||
*/
|
||||
#define ENTRY \
|
||||
#define LKMC_ENTRY \
|
||||
.text; \
|
||||
.global asm_main; \
|
||||
asm_main: \
|
||||
@@ -52,15 +52,15 @@ asm_main: \
|
||||
asm_main_after_prologue: \
|
||||
;
|
||||
|
||||
/* Meant to be called at the end of ENTRY.*
|
||||
/* Meant to be called at the end of LKMC_ENTRY.*
|
||||
*
|
||||
* Branching to "fail" makes tests fail with exit status 1.
|
||||
*
|
||||
* If EXIT is reached, the program ends successfully.
|
||||
* If LKMC_EXIT is reached, the program ends successfully.
|
||||
*
|
||||
* Restore LR and bx jump to it to return from asm_main.
|
||||
*/
|
||||
#define EXIT \
|
||||
#define LKMC_EXIT \
|
||||
mov r0, 0; \
|
||||
mov r1, 0; \
|
||||
b pass; \
|
||||
@@ -75,16 +75,9 @@ pass: \
|
||||
;
|
||||
|
||||
/* Always fail. */
|
||||
#define FAIL \
|
||||
#define LKMC_FAIL \
|
||||
ldr r0, =__LINE__; \
|
||||
b fail; \
|
||||
;
|
||||
|
||||
#define MEMCMP(s1, s2, n) \
|
||||
ldr r0, =s1; \
|
||||
ldr r1, =s2; \
|
||||
ldr r2, =n; \
|
||||
bl memcmp; \
|
||||
;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov r0, 0
|
||||
mov r1, 1
|
||||
cmp r0, 1
|
||||
/* Previous cmp failed, skip this operation. */
|
||||
addeq r1, 1
|
||||
ASSERT_EQ(r1, 1)
|
||||
LKMC_ASSERT_EQ(r1, 1)
|
||||
cmp r0, 0
|
||||
/* Previous passed, do this operation. */
|
||||
addeq r1, 1
|
||||
ASSERT_EQ(r1, 2)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 2)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -14,12 +14,12 @@ myquad:
|
||||
myocta:
|
||||
.octa 0x123456789ABCDEF0123456789ABCDEF0
|
||||
theend:
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
#define ASSERT_DIFF(label1, label2, result) \
|
||||
ldr r0, =label1; \
|
||||
ldr r1, =label2; \
|
||||
sub r0, r1, r0; \
|
||||
ASSERT_EQ(r0, result)
|
||||
LKMC_ASSERT_EQ(r0, result)
|
||||
|
||||
ASSERT_DIFF(mybyte, myword, 1)
|
||||
ASSERT_DIFF(myword, mylong, 4)
|
||||
@@ -27,4 +27,4 @@ ENTRY
|
||||
ASSERT_DIFF(myquad, myocta, 8)
|
||||
ASSERT_DIFF(myocta, theend, 16)
|
||||
#undef ASSERT_DIF
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* This is the default. We hack it in common.h however. */
|
||||
.syntax divided
|
||||
/* These fail. */
|
||||
@@ -21,4 +21,4 @@ ENTRY
|
||||
mov r0, 0x1
|
||||
mov r0, $1
|
||||
mov r0, $0x1
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -11,7 +11,7 @@ my_array:
|
||||
my_array_expect:
|
||||
.word 0x11111112, 0x22222223, 0x33333334, 0x44444445
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Increment. */
|
||||
ldr r0, =my_array
|
||||
mov r1, NELEM
|
||||
@@ -23,5 +23,5 @@ increment:
|
||||
sub r1, 1
|
||||
cmp r1, 0
|
||||
bne increment
|
||||
ASSERT_MEMCMP(my_array, my_array_expect, 0x10)
|
||||
EXIT
|
||||
LKMC_ASSERT_MEMCMP(my_array, my_array_expect, 0x10)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -11,7 +11,7 @@ my_array_0:
|
||||
my_array_1:
|
||||
.word 0x55555555, 0x66666666, 0x77777777, 0x88888888
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Load r5, r6, r7 and r8 starting from the address in r4. Don't change r4 */
|
||||
ldr r4, =my_array_0
|
||||
@@ -20,11 +20,11 @@ ENTRY
|
||||
ldr r7, =0
|
||||
ldr r8, =0
|
||||
ldmia r4, {r5-r8}
|
||||
ASSERT_EQ(r4, my_array_0)
|
||||
ASSERT_EQ(r5, 0x11111111)
|
||||
ASSERT_EQ(r6, 0x22222222)
|
||||
ASSERT_EQ(r7, 0x33333333)
|
||||
ASSERT_EQ(r8, 0x44444444)
|
||||
LKMC_ASSERT_EQ(r4, my_array_0)
|
||||
LKMC_ASSERT_EQ(r5, 0x11111111)
|
||||
LKMC_ASSERT_EQ(r6, 0x22222222)
|
||||
LKMC_ASSERT_EQ(r7, 0x33333333)
|
||||
LKMC_ASSERT_EQ(r8, 0x44444444)
|
||||
|
||||
/* Swapping the order of r5 and r6 on the mnemonic makes no difference to load order.
|
||||
*
|
||||
@@ -38,8 +38,8 @@ ENTRY
|
||||
ldr r5, =0
|
||||
ldr r6, =0
|
||||
ldmia r4, {r6,r5}
|
||||
ASSERT_EQ(r5, 0x11111111)
|
||||
ASSERT_EQ(r6, 0x22222222)
|
||||
LKMC_ASSERT_EQ(r5, 0x11111111)
|
||||
LKMC_ASSERT_EQ(r6, 0x22222222)
|
||||
#endif
|
||||
|
||||
/* Modify the array */
|
||||
@@ -51,11 +51,11 @@ ENTRY
|
||||
stmdb r4, {r5-r8}
|
||||
|
||||
/* Verify that my_array_0 changed and is equal to my_array_1. */
|
||||
ASSERT_MEMCMP(my_array_0, my_array_1, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(my_array_0, my_array_1, 0x10)
|
||||
|
||||
/* Load registers and increment r4. */
|
||||
ldr r4, =my_array_0
|
||||
ldmia r4!, {r5-r8}
|
||||
ASSERT_EQ(r4, my_array_1)
|
||||
LKMC_ASSERT_EQ(r4, my_array_1)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Mnemonic for a PC relative load:
|
||||
*
|
||||
@@ -12,13 +12,13 @@ ENTRY
|
||||
* ....
|
||||
*/
|
||||
ldr r0, myvar
|
||||
ASSERT_EQ(r0, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r0, 0x12345678)
|
||||
|
||||
/* Mnemonic PC relative load with an offset.
|
||||
* Load myvar2 instead of myvar.
|
||||
*/
|
||||
ldr r0, myvar + 4
|
||||
ASSERT_EQ(r0, 0x9ABCDEF0)
|
||||
LKMC_ASSERT_EQ(r0, 0x9ABCDEF0)
|
||||
|
||||
/* First store the address in r0 using a magic =myvar, which creates
|
||||
* a new variable containing the address and PC-relative addresses it
|
||||
@@ -33,17 +33,17 @@ ENTRY
|
||||
*/
|
||||
ldr r0, =myvar
|
||||
ldr r1, [r0]
|
||||
ASSERT_EQ(r1, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r1, 0x12345678)
|
||||
|
||||
/* More efficiently, use r0 as the address to read, and write to r0 itself. */
|
||||
ldr r0, =myvar
|
||||
ldr r0, [r0]
|
||||
ASSERT_EQ(r0, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r0, 0x12345678)
|
||||
|
||||
/* Same as =myvar but store a constant to a register.
|
||||
* Can also be done with movw and movt. */
|
||||
ldr r0, =0x11112222
|
||||
ASSERT_EQ(r0, 0x11112222)
|
||||
LKMC_ASSERT_EQ(r0, 0x11112222)
|
||||
|
||||
/* We can also use GAS tolower16 and topper16 and movw and movt
|
||||
* to load the address of myvar into r0 with two immediates.
|
||||
@@ -56,9 +56,9 @@ ENTRY
|
||||
movw r0, #:lower16:myvar
|
||||
movt r0, #:upper16:myvar
|
||||
ldr r1, [r0]
|
||||
ASSERT_EQ(r1, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r1, 0x12345678)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
myvar:
|
||||
.word 0x12345678
|
||||
myvar2:
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr r0, =myvar
|
||||
mov r1, 0x0
|
||||
ldrb r1, [r0]
|
||||
ASSERT_EQ(r1, 0x00000078)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 0x00000078)
|
||||
LKMC_EXIT
|
||||
myvar:
|
||||
.word 0x12345678
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr r0, =myvar
|
||||
mov r1, 0x0
|
||||
ldrh r1, [r0]
|
||||
ASSERT_EQ(r1, 0x00005678)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 0x00005678)
|
||||
LKMC_EXIT
|
||||
myvar:
|
||||
.word 0x12345678
|
||||
|
||||
@@ -12,21 +12,21 @@ my_array_0:
|
||||
my_array_1:
|
||||
.word 0x55555555, 0x66666666, 0x77777777, 0x88888888
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* puts("hello world") */
|
||||
/* r0 is first argument. */
|
||||
ldr r0, =puts_s
|
||||
bl puts
|
||||
/* Check exit status >= 0 for success. */
|
||||
cmp r0, 0
|
||||
ASSERT(bge)
|
||||
LKMC_ASSERT(bge)
|
||||
|
||||
/* printf */
|
||||
ldr r0, =printf_format
|
||||
ldr r1, =0x12345678
|
||||
bl printf
|
||||
cmp r0, 0
|
||||
ASSERT(bge)
|
||||
LKMC_ASSERT(bge)
|
||||
|
||||
/* memcpy and memcmp. */
|
||||
|
||||
@@ -36,7 +36,7 @@ ENTRY
|
||||
ldr r2, =0x10
|
||||
bl memcmp
|
||||
cmp r0, 0
|
||||
ASSERT(blt)
|
||||
LKMC_ASSERT(blt)
|
||||
|
||||
/* Copy. */
|
||||
ldr r0, =my_array_0
|
||||
@@ -49,11 +49,11 @@ ENTRY
|
||||
ldr r1, =my_array_1
|
||||
ldr r2, =0x10
|
||||
bl memcmp
|
||||
ASSERT_EQ(r0, 0)
|
||||
LKMC_ASSERT_EQ(r0, 0)
|
||||
|
||||
/* exit(0) */
|
||||
mov r0, 0
|
||||
bl exit
|
||||
|
||||
/* Never reached, just for the fail symbol. */
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Immediate. */
|
||||
mov r0, 0
|
||||
ASSERT_EQ(r0, 0)
|
||||
LKMC_ASSERT_EQ(r0, 0)
|
||||
mov r0, 1
|
||||
ASSERT_EQ(r0, 1)
|
||||
LKMC_ASSERT_EQ(r0, 1)
|
||||
|
||||
/* Register. */
|
||||
mov r0, 0
|
||||
mov r1, 1
|
||||
mov r1, r0
|
||||
ASSERT_EQ(r1, 0)
|
||||
LKMC_ASSERT_EQ(r1, 0)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* movt (top) and movw (TODO what is w) set the higher
|
||||
* and lower 16 bits of the register.
|
||||
@@ -10,7 +10,7 @@ ENTRY
|
||||
movw r0, 0xFFFF
|
||||
movt r0, 0x1234
|
||||
add r0, 1
|
||||
ASSERT_EQ(r0, 0x12350000)
|
||||
LKMC_ASSERT_EQ(r0, 0x12350000)
|
||||
|
||||
/* movw also zeroes out the top bits, allowing small 16-bit
|
||||
* C constants to be assigned in a single instruction.
|
||||
@@ -22,6 +22,6 @@ ENTRY
|
||||
*/
|
||||
ldr r0, =0x12345678
|
||||
movw r0, 0x1111
|
||||
ASSERT_EQ(r0, 0x00001111)
|
||||
LKMC_ASSERT_EQ(r0, 0x00001111)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* 2 * 3 = 6 */
|
||||
mov r0, 0
|
||||
mov r1, 2
|
||||
mov r2, 3
|
||||
mul r1, r2
|
||||
ASSERT_EQ(r1, 6)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 6)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Disassembles as:
|
||||
*
|
||||
* ....
|
||||
@@ -29,4 +29,4 @@ ENTRY
|
||||
|
||||
/* And there are other nops as well? Disassembles as `and`. */
|
||||
and r0, r0, r0
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Save sp before push. */
|
||||
mov r4, sp
|
||||
@@ -19,13 +19,13 @@ ENTRY
|
||||
mov r7, 0
|
||||
mov r8, 0
|
||||
pop {r7, r8}
|
||||
ASSERT_EQ(r7, 1)
|
||||
ASSERT_EQ(r8, 2)
|
||||
LKMC_ASSERT_EQ(r7, 1)
|
||||
LKMC_ASSERT_EQ(r8, 2)
|
||||
|
||||
/* Check that stack pointer moved down by 8 bytes
|
||||
* (2 registers x 4 bytes each).
|
||||
*/
|
||||
sub r4, r5
|
||||
ASSERT_EQ(r4, 8)
|
||||
LKMC_ASSERT_EQ(r4, 8)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
ldr r0, =0b00000001001000110100010101100101
|
||||
rbit r1, r0
|
||||
ASSERT_EQ(r1, 0b10100110101000101100010010000000)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 0b10100110101000101100010010000000)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* 13 general purpose registers. */
|
||||
mov r0, 0
|
||||
@@ -39,12 +39,12 @@ ENTRY
|
||||
* https://stackoverflow.com/questions/32304646/arm-assembly-branch-to-address-inside-register-or-memory/54145818#54145818
|
||||
*/
|
||||
ldr pc, =10f
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
10:
|
||||
|
||||
/* Same with r15, which is the same as pc. */
|
||||
ldr r15, =10f
|
||||
FAIL
|
||||
LKMC_FAIL
|
||||
10:
|
||||
|
||||
/* Another example with mov reading from pc. */
|
||||
@@ -60,10 +60,10 @@ pc_addr:
|
||||
b 1f
|
||||
.word 0x12345678
|
||||
1:
|
||||
ASSERT_EQ(r0, 0x12345678)
|
||||
LKMC_ASSERT_EQ(r0, 0x12345678)
|
||||
|
||||
/* We can also use fp in GNU GAS assembly. */
|
||||
mov r11, 0
|
||||
mov fp, 1
|
||||
ASSERT_EQ(r11, 1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r11, 1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* All bytes in register. */
|
||||
ldr r0, =0x11223344
|
||||
rev r1, r0
|
||||
ASSERT_EQ(r1, 0x44332211)
|
||||
LKMC_ASSERT_EQ(r1, 0x44332211)
|
||||
|
||||
/* Groups of 16-bits. */
|
||||
ldr r0, =0x11223344
|
||||
rev16 r1, r0
|
||||
ASSERT_EQ(r1, 0x22114433)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r1, 0x22114433)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* Result is 0, set beq. */
|
||||
movs r0, 0
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* The opposite. */
|
||||
movs r0, 1
|
||||
ASSERT(bne)
|
||||
LKMC_ASSERT(bne)
|
||||
|
||||
/* mov without s does not set the status. */
|
||||
movs r0, 0
|
||||
mov r0, 1
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* movs still moves... */
|
||||
mov r0, 0
|
||||
movs r0, 1
|
||||
ASSERT_EQ(r0, 1)
|
||||
LKMC_ASSERT_EQ(r0, 1)
|
||||
|
||||
/* add: the result is 0. */
|
||||
mov r0, 1
|
||||
adds r0, -1
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* add: result non 0. */
|
||||
mov r0, 1
|
||||
adds r0, 1
|
||||
ASSERT(bne)
|
||||
LKMC_ASSERT(bne)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* lsr */
|
||||
ldr r0, =0xFFF00FFF
|
||||
mov r1, r0, lsl 8
|
||||
ldr r2, =0xF00FFF00
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* lsl */
|
||||
ldr r0, =0xFFF00FFF
|
||||
mov r1, r0, lsr 8
|
||||
ldr r2, =0x00FFF00F
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* ror */
|
||||
ldr r0, =0xFFF00FFF
|
||||
mov r1, r0, ror 8
|
||||
ldr r2, =0xFFFFF00F
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* asr negative */
|
||||
ldr r0, =0x80000008
|
||||
mov r1, r0, asr 1
|
||||
ldr r2, =0xC0000004
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* asr positive */
|
||||
ldr r0, =0x40000008
|
||||
mov r1, r0, asr 1
|
||||
ldr r2, =0x20000004
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* There are also direct shift mnemonics for the mov shifts.
|
||||
*
|
||||
@@ -41,7 +41,7 @@ ENTRY
|
||||
ldr r0, =0xFFF00FFF
|
||||
lsl r1, r0, 8
|
||||
ldr r2, =0xF00FFF00
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* If used with the `mov` instruction, it results in a pure shift,
|
||||
* but the suffixes also exist for all the other data processing instructions.
|
||||
@@ -56,7 +56,7 @@ ENTRY
|
||||
ldr r1, =0x100
|
||||
add r1, r1, r0, lsl 1
|
||||
ldr r2, =0x00000120
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* The shift takes up the same encoding slot as the immediate,
|
||||
* therefore it is not possible to both use an immediate and shift.
|
||||
@@ -74,6 +74,6 @@ ENTRY
|
||||
ldr r1, =0x100
|
||||
add r1, r1, (0x10 << 1)
|
||||
ldr r2, =0x00000120
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
myvar:
|
||||
.word 0x12345678
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Sanity check. */
|
||||
ldr r0, =myvar
|
||||
ldr r1, [r0]
|
||||
movw r2, 0x5678
|
||||
movt r2, 0x1234
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* Modify the value. */
|
||||
ldr r0, =myvar
|
||||
@@ -26,7 +26,7 @@ ENTRY
|
||||
ldr r1, [r0]
|
||||
movw r2, 0xDEF0
|
||||
movt r2, 0x9ABC
|
||||
ASSERT_EQ_REG(r1, r2)
|
||||
LKMC_ASSERT_EQ_REG(r1, r2)
|
||||
|
||||
/* Cannot use PC relative addressing to a different segment,
|
||||
* or else it fails with:
|
||||
@@ -57,4 +57,4 @@ var_in_same_section:
|
||||
str r1, =myvar
|
||||
#endif
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* 3 - 2 == 1 , register version.*/
|
||||
mov r0, 3
|
||||
mov r1, 2
|
||||
sub r0, r0, r1
|
||||
ASSERT_EQ(r0, 1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(r0, 1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
|
||||
/* 0x0F && 0xF0 == 0x00, so beq. */
|
||||
mov r0, 0x0F
|
||||
tst r0, 0xF0
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* bne */
|
||||
mov r0, 0xFF
|
||||
tst r0, 0x0F
|
||||
ASSERT(bne)
|
||||
LKMC_ASSERT(bne)
|
||||
# r0 was not modified.
|
||||
ASSERT_EQ(r0, 0xFF)
|
||||
LKMC_ASSERT_EQ(r0, 0xFF)
|
||||
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
udf 0
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Minimal single precision floating point example.
|
||||
* TODO: floating point representation constraints due to 4-byte instruction?
|
||||
*/
|
||||
@@ -18,7 +18,7 @@ ENTRY
|
||||
/* Move the nzcv bits from fpscr to apsr */
|
||||
vmrs apsr_nzcv, fpscr
|
||||
/* This branch uses the Z bit of apsr, which was set accordingly. */
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* Now the same from memory with vldr and vstr. */
|
||||
.data
|
||||
@@ -39,7 +39,7 @@ my_float_sum:
|
||||
vadd.f32 s2, s0, s1
|
||||
ldr r0, =my_float_sum
|
||||
vstr.f32 s2, [r0]
|
||||
ASSERT_MEMCMP(my_float_sum, my_float_sum_expect, 4)
|
||||
LKMC_ASSERT_MEMCMP(my_float_sum, my_float_sum_expect, 4)
|
||||
|
||||
#if 0
|
||||
/* We can't do pseudo vldr as for ldr, fails with:
|
||||
@@ -56,7 +56,7 @@ my_float_sum:
|
||||
vmov.f64 d3, 4.0
|
||||
vcmp.f64 d2, d3
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* vmov can also move to general purpose registers.
|
||||
*
|
||||
@@ -68,5 +68,5 @@ my_float_sum:
|
||||
vmov s0, r0
|
||||
vmov s1, s0
|
||||
vmov r1, s1
|
||||
ASSERT_EQ_REG(r0, r1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ_REG(r0, r1)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
.bss
|
||||
output: .skip 16
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* Integer. */
|
||||
.data
|
||||
input0_u: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
|
||||
@@ -20,7 +20,7 @@ ENTRY
|
||||
vadd.u ## size q2, q0, q1; \
|
||||
ldr r0, =output; \
|
||||
vst1.u ## size {q2}, [r0]; \
|
||||
ASSERT_MEMCMP(output, expect_u_ ## size, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, expect_u_ ## size, 0x10)
|
||||
|
||||
/* vadd.u32
|
||||
*
|
||||
@@ -54,7 +54,7 @@ ENTRY
|
||||
vadd.f ## size q2, q0, q1; \
|
||||
ldr r0, =output; \
|
||||
vst1. ## size {q2}, [r0]; \
|
||||
ASSERT_MEMCMP(output, expect_f_ ## size, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, expect_f_ ## size, 0x10)
|
||||
|
||||
/* 4x 32-bit. */
|
||||
TEST(32)
|
||||
@@ -68,4 +68,4 @@ ENTRY
|
||||
TEST(64)
|
||||
#endif
|
||||
#undef TEST
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* SIMD positive. */
|
||||
.data
|
||||
vcvt_positive_0: .float 1.25, 2.5, 3.75, 4.0
|
||||
@@ -15,7 +15,7 @@ ENTRY
|
||||
vcvt.u32.f32 q1, q0
|
||||
ldr r0, =vcvt_positive_result
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(vcvt_positive_result, vcvt_positive_expect, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(vcvt_positive_result, vcvt_positive_expect, 0x10)
|
||||
|
||||
/* SIMD negative. */
|
||||
.data
|
||||
@@ -29,7 +29,7 @@ ENTRY
|
||||
vcvt.s32.f32 q1, q0
|
||||
ldr r0, =vcvt_negative_result
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(vcvt_negative_result, vcvt_negative_expect, 0x10)
|
||||
LKMC_ASSERT_MEMCMP(vcvt_negative_result, vcvt_negative_expect, 0x10)
|
||||
|
||||
/* Floating point. */
|
||||
.data
|
||||
@@ -44,7 +44,7 @@ ENTRY
|
||||
vcvt.u32.f32 s0, s0
|
||||
ldr r0, =vcvt_positive_float_result
|
||||
vst1.32 {d0}, [r0]
|
||||
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.
|
||||
*
|
||||
@@ -63,12 +63,12 @@ ENTRY
|
||||
vmov.i32 d1, 1
|
||||
vcmp.f32 s0, s2
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
/* Check that s1 wasn't modified by vcvt. */
|
||||
vmov.f32 s2, 1.5
|
||||
vcmp.f32 s1, s2
|
||||
vmrs apsr_nzcv, fpscr
|
||||
ASSERT(beq)
|
||||
LKMC_ASSERT(beq)
|
||||
|
||||
/* Floating point double precision. */
|
||||
.data
|
||||
@@ -82,9 +82,9 @@ ENTRY
|
||||
vcvt.u32.f64 s0, d0
|
||||
ldr r0, =vcvt_positive_double_result
|
||||
vst1.32 {d0}, [r0]
|
||||
ASSERT_MEMCMP(
|
||||
LKMC_ASSERT_MEMCMP(
|
||||
vcvt_positive_double_result,
|
||||
vcvt_positive_double_expect,
|
||||
0x4
|
||||
)
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
/* SIMD positive. */
|
||||
.data
|
||||
vcvta_positive_0: .float 1.25, 2.5, 3.75, 4.0
|
||||
@@ -15,7 +15,7 @@ ENTRY
|
||||
vcvta.u32.f32 q1, q0
|
||||
ldr r0, =vcvta_positive_result
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(
|
||||
LKMC_ASSERT_MEMCMP(
|
||||
vcvta_positive_result,
|
||||
vcvta_positive_expect,
|
||||
0x10
|
||||
@@ -33,9 +33,9 @@ ENTRY
|
||||
vcvta.s32.f32 q1, q0
|
||||
ldr r0, =vcvta_negative_result
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(
|
||||
LKMC_ASSERT_MEMCMP(
|
||||
vcvta_negative_result,
|
||||
vcvta_negative_expect,
|
||||
0x10
|
||||
)
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.data
|
||||
vcvtr_0: .float 1.25, 2.5, 3.75, 4.0
|
||||
vcvtr_expect_zero: .word 1, 2, 3, 4
|
||||
@@ -21,7 +21,7 @@ ENTRY
|
||||
vcvtr.u32.f32 q1, q0
|
||||
ldr r0, =vcvtr_result_zero
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(
|
||||
LKMC_ASSERT_MEMCMP(
|
||||
vcvtr_result_zero,
|
||||
vcvtr_expect_zero,
|
||||
0x10
|
||||
@@ -37,10 +37,10 @@ ENTRY
|
||||
vcvtr.u32.f32 q1, q0
|
||||
ldr r0, =vcvtr_result_plus_infinity
|
||||
vst1.32 {q1}, [r0]
|
||||
ASSERT_MEMCMP(
|
||||
LKMC_ASSERT_MEMCMP(
|
||||
vcvtr_result_plus_infinity,
|
||||
vcvtr_expect_plus_infinity,
|
||||
0x10
|
||||
)
|
||||
#endif
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
;
|
||||
|
||||
/* Assert that the given branch instruction is taken. */
|
||||
#define ASSERT(branch_if_pass) \
|
||||
#define LKMC_ASSERT(branch_if_pass) \
|
||||
branch_if_pass 1f; \
|
||||
FAIL; \
|
||||
LKMC_FAIL; \
|
||||
1: \
|
||||
;
|
||||
|
||||
#ifndef ASSERT_EQ_REG
|
||||
#ifndef LKMC_ASSERT_EQ_REG
|
||||
/* Assert that a register equals another register. */
|
||||
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||
#define LKMC_ASSERT_EQ_REG(reg1, reg2) \
|
||||
cmp reg1, reg2; \
|
||||
ASSERT(beq); \
|
||||
LKMC_ASSERT(beq); \
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
EXIT
|
||||
LKMC_ENTRY
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* See what happens on test failure with FAIL.
|
||||
/* See what happens on test failure with LKMC_FAIL.
|
||||
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
FAIL
|
||||
EXIT
|
||||
LKMC_ENTRY
|
||||
LKMC_FAIL
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lkmc.h>
|
||||
|
||||
int asm_main(uint32_t *line);
|
||||
|
||||
#define ASSERT_EQ_DEFINE(bits) \
|
||||
int assert_eq_ ## bits(uint ## bits ## _t val1, uint ## bits ## _t val2) { \
|
||||
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); \
|
||||
@@ -19,11 +18,11 @@ int asm_main(uint32_t *line);
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
ASSERT_EQ_DEFINE(32)
|
||||
ASSERT_EQ_DEFINE(64)
|
||||
#undef ASSERT_EQ_DEFINE
|
||||
|
||||
int assert_memcmp(const void *s1, const void *s2, size_t n) {
|
||||
int lkmc_assert_memcmp(const void *s1, const void *s2, size_t n) {
|
||||
int ret;
|
||||
size_t i;
|
||||
uint8_t *s1b, *s2b;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov $1, %rax
|
||||
add $2, %rax
|
||||
ASSERT_EQ(%rax, $3)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(%rax, $3)
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.bss
|
||||
output: .skip 16
|
||||
.data
|
||||
@@ -21,11 +21,11 @@ ENTRY
|
||||
movups addp ## size ## _input1, %xmm1; \
|
||||
addp ## size %xmm1, %xmm0; \
|
||||
movups %xmm0, output; \
|
||||
ASSERT_MEMCMP(output, addp ## size ## _expect, $0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, addp ## size ## _expect, $0x10)
|
||||
|
||||
/* 4x 32-bit */
|
||||
TEST(s)
|
||||
/* 2x 64-bit */
|
||||
TEST(d)
|
||||
#undef TEST
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
@@ -5,32 +5,32 @@
|
||||
|
||||
/* This and other macros may make C function calls, and therefore can destroy
|
||||
* non-callee saved registers. */
|
||||
#define ASSERT_EQ(general1, general2) \
|
||||
#define LKMC_ASSERT_EQ(general1, general2) \
|
||||
mov general2, %rdi; \
|
||||
push %rdi; \
|
||||
mov general1, %rdi; \
|
||||
pop %rsi; \
|
||||
ASSERT_EQ_DO(64); \
|
||||
LKMC_ASSERT_EQ_DO(64); \
|
||||
;
|
||||
|
||||
#define ASSERT_EQ_DO(bits) \
|
||||
call assert_eq_ ## bits; \
|
||||
#define LKMC_ASSERT_EQ_DO(bits) \
|
||||
call lkmc_assert_eq_ ## bits; \
|
||||
cmp $0, %rax; \
|
||||
ASSERT(je); \
|
||||
LKMC_ASSERT(je); \
|
||||
;
|
||||
|
||||
#define ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
#define LKMC_ASSERT_MEMCMP(label1, label2, const_size) \
|
||||
lea label1(%rip), %rdi; \
|
||||
lea label2(%rip), %rsi; \
|
||||
mov const_size, %rdx; \
|
||||
call assert_memcmp; \
|
||||
call lkmc_assert_memcmp; \
|
||||
cmp $0, %rax; \
|
||||
ASSERT(je); \
|
||||
LKMC_ASSERT(je); \
|
||||
;
|
||||
|
||||
/* Program entry point.
|
||||
*
|
||||
* Return with EXIT.
|
||||
* Return with LKMC_EXIT.
|
||||
*
|
||||
* Basically implements an x86_64 prologue:
|
||||
*
|
||||
@@ -38,7 +38,7 @@
|
||||
* 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 ENTRY \
|
||||
#define LKMC_ENTRY \
|
||||
.text; \
|
||||
.global asm_main; \
|
||||
asm_main: \
|
||||
@@ -54,13 +54,13 @@ asm_main: \
|
||||
asm_main_after_prologue: \
|
||||
;
|
||||
|
||||
/* Meant to be called at the end of ENTRY.*
|
||||
/* Meant to be called at the end of LKMC_ENTRY.*
|
||||
*
|
||||
* Branching to "fail" makes tests fail with exit status 1.
|
||||
*
|
||||
* If EXIT is reached, the program ends successfully.
|
||||
* If LKMC_EXIT is reached, the program ends successfully.
|
||||
*/
|
||||
#define EXIT \
|
||||
#define LKMC_EXIT \
|
||||
mov $0, %rax; \
|
||||
jmp pass; \
|
||||
fail: \
|
||||
@@ -79,7 +79,7 @@ pass: \
|
||||
ret; \
|
||||
;
|
||||
|
||||
#define FAIL \
|
||||
#define LKMC_FAIL \
|
||||
mov $__LINE__, %eax; \
|
||||
jmp fail; \
|
||||
;
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
#define ASSERT_DIFF(label1, label2, result) \
|
||||
lea label2(%rip), %rax; \
|
||||
lea label1(%rip), %rbx; \
|
||||
sub %rbx, %rax; \
|
||||
ASSERT_EQ(%rax, $result)
|
||||
LKMC_ASSERT_EQ(%rax, $result)
|
||||
|
||||
ASSERT_DIFF(mybyte, myword, 1)
|
||||
ASSERT_DIFF(myword, mylong, 2)
|
||||
@@ -15,7 +15,7 @@ ENTRY
|
||||
ASSERT_DIFF(myquad, myocta, 8)
|
||||
ASSERT_DIFF(myocta, theend, 16)
|
||||
#undef ASSERT_DIF
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
mybyte:
|
||||
.byte 0x12
|
||||
myword:
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
mov $0x123456789ABCDEF0, %r12
|
||||
mov $0x123456789ABCDEF0, %r13
|
||||
ASSERT_EQ(%r12, $0x123456789ABCDEF0)
|
||||
ASSERT_EQ(%r12, %r13)
|
||||
ASSERT_EQ(%r12, myvar)
|
||||
ASSERT_EQ($0x123456789ABCDEF0, %r12)
|
||||
ASSERT_EQ(%r13, %r12)
|
||||
ASSERT_EQ(myvar, %r12)
|
||||
ASSERT_EQ(%r12, $0x123456789ABCDEF1)
|
||||
EXIT
|
||||
LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF0)
|
||||
LKMC_ASSERT_EQ(%r12, %r13)
|
||||
LKMC_ASSERT_EQ(%r12, myvar)
|
||||
LKMC_ASSERT_EQ($0x123456789ABCDEF0, %r12)
|
||||
LKMC_ASSERT_EQ(%r13, %r12)
|
||||
LKMC_ASSERT_EQ(myvar, %r12)
|
||||
LKMC_ASSERT_EQ(%r12, $0x123456789ABCDEF1)
|
||||
LKMC_EXIT
|
||||
myvar: .quad 0x123456789ABCDEF0
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
ASSERT_MEMCMP(var0, var1, $0x10)
|
||||
ASSERT_MEMCMP(var0, var2, $0x10)
|
||||
EXIT
|
||||
LKMC_ENTRY
|
||||
LKMC_ASSERT_MEMCMP(var0, var1, $0x10)
|
||||
LKMC_ASSERT_MEMCMP(var0, var2, $0x10)
|
||||
LKMC_EXIT
|
||||
var0: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
|
||||
var1: .long 0x11111111, 0x22222222, 0x33333333, 0x44444444
|
||||
var2: .long 0x11111111, 0x22222223, 0x23333333, 0x44444444
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
ENTRY
|
||||
LKMC_ENTRY
|
||||
.data
|
||||
input0: .long 0xF1F1F1F1, 0xF2F2F2F2, 0xF3F3F3F3, 0xF4F4F4F4
|
||||
input1: .long 0x12121212, 0x13131313, 0x14141414, 0x15151515
|
||||
@@ -23,7 +23,7 @@ ENTRY
|
||||
movups input0, %xmm0; \
|
||||
padd ## size %xmm1, %xmm0; \
|
||||
movups %xmm0, output; \
|
||||
ASSERT_MEMCMP(output, padd ## size ## _expect, $0x10)
|
||||
LKMC_ASSERT_MEMCMP(output, padd ## size ## _expect, $0x10)
|
||||
|
||||
/* 16x 8-bit */
|
||||
TEST(b)
|
||||
@@ -35,4 +35,4 @@ ENTRY
|
||||
/* 2x 16-bit */
|
||||
TEST(q)
|
||||
#undef TEST
|
||||
EXIT
|
||||
LKMC_EXIT
|
||||
|
||||
Reference in New Issue
Block a user