mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-27 20:14:27 +01:00
userland: start refactor to show failing values on failure!
aarch64 basically done, but missing: - other archs - maybe convert main.c into C++ to use templates? - full review of ASSERT_EQ calling convention issues not seen by tests by chance - documentation
This commit is contained in:
@@ -4,31 +4,55 @@
|
|||||||
#define COMMON_ARCH_H
|
#define COMMON_ARCH_H
|
||||||
|
|
||||||
#define ASSERT_EQ(reg, const) \
|
#define ASSERT_EQ(reg, const) \
|
||||||
ldr x11, =const; \
|
mov x0, reg; \
|
||||||
cmp reg, x11; \
|
ldr x1, =const; \
|
||||||
|
ASSERT_EQ_DO(64); \
|
||||||
|
;
|
||||||
|
|
||||||
|
#define ASSERT_EQ_DO(bits) \
|
||||||
|
bl assert_eq_ ## bits; \
|
||||||
|
cmp x0, 0; \
|
||||||
ASSERT(beq); \
|
ASSERT(beq); \
|
||||||
;
|
;
|
||||||
|
|
||||||
#define ASSERT_MEMCMP(s1, s2, n) \
|
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||||
MEMCMP(s1, s2, n); \
|
str reg2, [sp, -8]!; \
|
||||||
ASSERT_EQ(x0, 0); \
|
mov x0, reg1; \
|
||||||
|
ldr x1, [sp], 8; \
|
||||||
|
ASSERT_EQ_DO(64); \
|
||||||
|
;
|
||||||
|
|
||||||
|
#define ASSERT_EQ_REG_32(reg1, reg2) \
|
||||||
|
str reg2, [sp, -4]!; \
|
||||||
|
mov w0, reg1; \
|
||||||
|
ldr w1, [sp], 4; \
|
||||||
|
ASSERT_EQ_DO(32); \
|
||||||
|
;
|
||||||
|
|
||||||
|
#define ASSERT_MEMCMP(label1, label2, const_size) \
|
||||||
|
adr x0, label1; \
|
||||||
|
adr x1, label2; \
|
||||||
|
ldr x2, =const_size; \
|
||||||
|
bl assert_memcmp; \
|
||||||
|
cmp x0, 0; \
|
||||||
|
ASSERT(beq); \
|
||||||
;
|
;
|
||||||
|
|
||||||
#define ENTRY \
|
#define ENTRY \
|
||||||
.text; \
|
.text; \
|
||||||
.global asm_main; \
|
.global asm_main; \
|
||||||
asm_main: \
|
asm_main: \
|
||||||
sub sp, sp, 0xA0; \
|
sub sp, sp, 0xA0; \
|
||||||
stp x29, x30, [sp]; \
|
stp x29, x30, [sp]; \
|
||||||
stp x27, x28, [sp, 0x10]; \
|
stp x27, x28, [sp, 0x10]; \
|
||||||
stp x25, x26, [sp, 0x20]; \
|
stp x25, x26, [sp, 0x20]; \
|
||||||
stp x23, x24, [sp, 0x30]; \
|
stp x23, x24, [sp, 0x30]; \
|
||||||
stp x21, x22, [sp, 0x40]; \
|
stp x21, x22, [sp, 0x40]; \
|
||||||
stp x19, x20, [sp, 0x50]; \
|
stp x19, x20, [sp, 0x50]; \
|
||||||
stp x6, x7, [sp, 0x60]; \
|
stp x6, x7, [sp, 0x60]; \
|
||||||
stp x4, x5, [sp, 0x70]; \
|
stp x4, x5, [sp, 0x70]; \
|
||||||
stp x2, x3, [sp, 0x80]; \
|
stp x2, x3, [sp, 0x80]; \
|
||||||
stp x0, x1, [sp, 0x90]; \
|
stp x0, x1, [sp, 0x90]; \
|
||||||
asm_main_after_prologue: \
|
asm_main_after_prologue: \
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -56,11 +80,4 @@ pass: \
|
|||||||
b fail; \
|
b fail; \
|
||||||
;
|
;
|
||||||
|
|
||||||
#define MEMCMP(s1, s2, n) \
|
|
||||||
adr x0, s1; \
|
|
||||||
adr x1, s2; \
|
|
||||||
ldr x2, =n; \
|
|
||||||
bl memcmp; \
|
|
||||||
;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,25 +4,25 @@
|
|||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
/* Test values. */
|
/* Test values. */
|
||||||
mov x0, 0
|
mov x19, 0
|
||||||
mov x1, 1
|
mov x20, 1
|
||||||
|
|
||||||
/* eq is true, set x2 = 1. */
|
/* eq is true, set x21 = 1. */
|
||||||
cmp x0, x0
|
cmp x19, x19
|
||||||
cset x2, eq
|
cset x21, eq
|
||||||
ASSERT_EQ(x2, 1)
|
ASSERT_EQ(x21, 1)
|
||||||
|
|
||||||
/* eq is false, set x2 = 0. */
|
/* eq is false, set x21 = 0. */
|
||||||
cmp x0, x1
|
cmp x19, x20
|
||||||
cset x2, eq
|
cset x21, eq
|
||||||
ASSERT_EQ(x2, 0)
|
ASSERT_EQ(x21, 0)
|
||||||
|
|
||||||
/* Same for ne. */
|
/* Same for ne. */
|
||||||
cmp x0, x0
|
cmp x19, x19
|
||||||
cset x2, ne
|
cset x21, ne
|
||||||
ASSERT_EQ(x2, 0)
|
ASSERT_EQ(x21, 0)
|
||||||
|
|
||||||
cmp x0, x1
|
cmp x19, x20
|
||||||
cset x2, ne
|
cset x21, ne
|
||||||
ASSERT_EQ(x2, 1)
|
ASSERT_EQ(x21, 1)
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -3,26 +3,26 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
mov x0, 1
|
mov x19, 1
|
||||||
bl inc
|
bl inc
|
||||||
ASSERT_EQ(x0, 2)
|
ASSERT_EQ(x19, 2)
|
||||||
bl inc2
|
bl inc2
|
||||||
ASSERT_EQ(x0, 3)
|
ASSERT_EQ(x19, 3)
|
||||||
bl inc3
|
bl inc3
|
||||||
ASSERT_EQ(x0, 4)
|
ASSERT_EQ(x19, 4)
|
||||||
EXIT
|
EXIT
|
||||||
|
|
||||||
/* void inc(uint64_t *i) { (*i)++ } */
|
/* void inc(uint64_t *i) { (*i)++ } */
|
||||||
inc:
|
inc:
|
||||||
add x0, x0, 1
|
add x19, x19, 1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
/* Same but explicit return register. */
|
/* Same but explicit return register. */
|
||||||
inc2:
|
inc2:
|
||||||
add x0, x0, 1
|
add x19, x19, 1
|
||||||
ret x30
|
ret x30
|
||||||
|
|
||||||
/* Same but with br. */
|
/* Same but with br. */
|
||||||
inc3:
|
inc3:
|
||||||
add x0, x0, 1
|
add x19, x19, 1
|
||||||
br x30
|
br x30
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
ldr x0, =0x1122334455667788
|
ldr x19, =0x1122334455667788
|
||||||
|
|
||||||
// lsr alias: imms == 63
|
// lsr alias: imms == 63
|
||||||
|
|
||||||
ldr x1, =0xFFFFFFFFFFFFFFFF
|
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||||
ubfm x1, x0, 16, 63
|
ubfm x20, x19, 16, 63
|
||||||
ASSERT_EQ(x1, 0x0000112233445566)
|
ASSERT_EQ(x20, 0x0000112233445566)
|
||||||
|
|
||||||
ldr x1, =0xFFFFFFFFFFFFFFFF
|
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||||
ubfm x1, x0, 32, 63
|
ubfm x20, x19, 32, 63
|
||||||
ASSERT_EQ(x1, 0x0000000011223344)
|
ASSERT_EQ(x20, 0x0000000011223344)
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
ldr x0, =0x1122334455667788
|
ldr x19, =0x1122334455667788
|
||||||
|
|
||||||
ldr x1, =0xFFFFFFFFFFFFFFFF
|
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||||
ubfx x1, x0, 8, 16
|
ubfx x20, x19, 8, 16
|
||||||
ASSERT_EQ(x1, 0x0000000000006677)
|
ASSERT_EQ(x20, 0x0000000000006677)
|
||||||
|
|
||||||
ldr x1, =0xFFFFFFFFFFFFFFFF
|
ldr x20, =0xFFFFFFFFFFFFFFFF
|
||||||
ubfx x1, x0, 8, 32
|
ubfx x20, x19, 8, 32
|
||||||
ASSERT_EQ(x1, 0x0000000044556677)
|
ASSERT_EQ(x20, 0x0000000044556677)
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ ENTRY
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* mov (register) is an alias for ORR, which accepts xzr. */
|
/* mov (register) is an alias for ORR, which accepts xzr. */
|
||||||
mov x0, 1
|
mov x19, 1
|
||||||
mov x0, xzr
|
mov x19, xzr
|
||||||
ASSERT_EQ(x0, 0)
|
ASSERT_EQ(x19, 0)
|
||||||
|
|
||||||
/* Same encoding as the mov version. */
|
/* Same encoding as the mov version. */
|
||||||
mov x0, 1
|
mov x19, 1
|
||||||
orr x0, xzr, xzr
|
orr x19, xzr, xzr
|
||||||
ASSERT_EQ(x0, 0)
|
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
|
||||||
@@ -24,19 +24,19 @@ ENTRY
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Zero register discards result if written to. */
|
/* Zero register discards result if written to. */
|
||||||
mov x0, 1
|
mov x19, 1
|
||||||
orr xzr, x0, x0
|
orr xzr, x19, x19
|
||||||
ASSERT_EQ(xzr, 0)
|
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 x0, sp
|
mov x19, sp
|
||||||
mov sp, 1
|
mov sp, 1
|
||||||
/* Alias to add. */
|
/* Alias to add. */
|
||||||
mov x1, sp
|
mov x20, sp
|
||||||
/* Exact same encoding as above. */
|
/* Exact same encoding as above. */
|
||||||
add x1, sp, 0
|
add x20, sp, 0
|
||||||
ASSERT_EQ(x1, 1)
|
mov sp, x19
|
||||||
mov sp, x0
|
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
|
||||||
|
|||||||
@@ -4,48 +4,48 @@
|
|||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
|
|
||||||
/* Offset mode with immediate. Add 4 to the address register, which ends up
|
/* Offset mode with immediate. Add 4 to the address register,
|
||||||
* reading myvar2 instead of myvar.
|
* which ends up * reading myvar6 instead of myvar.
|
||||||
*/
|
*/
|
||||||
adr r0, myvar
|
adr r4, myvar
|
||||||
ldr r1, [r0, 4]
|
ldr r5, [r4, 4]
|
||||||
ASSERT_EQ(r1, 0x9ABCDEF0)
|
ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||||
/* r0 was not modified. */
|
/* r4 was not modified. */
|
||||||
ASSERT_EQ(r0, myvar)
|
ASSERT_EQ(r4, myvar)
|
||||||
|
|
||||||
/* Pre-indexed mode */
|
/* Pre-indexed mode: modify register, then use it. */
|
||||||
adr r0, myvar
|
adr r4, myvar
|
||||||
ldr r1, [r0, 4]!
|
ldr r5, [r4, 4]!
|
||||||
ASSERT_EQ(r1, 0x9ABCDEF0)
|
ASSERT_EQ(r5, 0x9ABCDEF0)
|
||||||
/* r0 was modified. */
|
/* r4 was modified. */
|
||||||
ASSERT_EQ(r0, myvar2)
|
ASSERT_EQ(r4, myvar6)
|
||||||
|
|
||||||
/* Post-indexed mode */
|
/* Post-indexed mode: use register, then modify it. */
|
||||||
adr r0, myvar
|
adr r4, myvar
|
||||||
ldr r1, [r0], 4
|
ldr r5, [r4], 4
|
||||||
ASSERT_EQ(r1, 0x12345678)
|
ASSERT_EQ(r5, 0x12345678)
|
||||||
/* r0 was modified. */
|
/* r4 was modified. */
|
||||||
ASSERT_EQ(r0, myvar2)
|
ASSERT_EQ(r4, myvar6)
|
||||||
|
|
||||||
/* Offset in register. */
|
/* Offset in register. */
|
||||||
adr r0, myvar
|
adr r4, myvar
|
||||||
mov r1, 4
|
mov r5, 4
|
||||||
ldr r2, [r0, r1]
|
ldr r6, [r4, r5]
|
||||||
ASSERT_EQ(r2, 0x9ABCDEF0)
|
ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||||
|
|
||||||
/* Offset in shifted register:
|
/* Offset in shifted register:
|
||||||
* r2 =
|
* r6 =
|
||||||
* (r0 + (r1 << 1))
|
* (r4 + (r5 << 1))
|
||||||
* == *(myvar + (2 << 1))
|
* == *(myvar + (2 << 1))
|
||||||
* == *(myvar + 4)
|
* == *(myvar + 4)
|
||||||
*/
|
*/
|
||||||
adr r0, myvar
|
adr r4, myvar
|
||||||
mov r1, 2
|
mov r5, 2
|
||||||
ldr r2, [r0, r1, lsl 1]
|
ldr r6, [r4, r5, lsl 1]
|
||||||
ASSERT_EQ(r2, 0x9ABCDEF0)
|
ASSERT_EQ(r6, 0x9ABCDEF0)
|
||||||
|
|
||||||
EXIT
|
EXIT
|
||||||
myvar:
|
myvar:
|
||||||
.word 0x12345678
|
.word 0x12345678
|
||||||
myvar2:
|
myvar6:
|
||||||
.word 0x9ABCDEF0
|
.word 0x9ABCDEF0
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
data_label:
|
data_label:
|
||||||
.word 0x1234678
|
.word 0x1234678
|
||||||
ENTRY
|
ENTRY
|
||||||
adr r0, 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
|
||||||
* alternative here.
|
* alternative here.
|
||||||
*/
|
*/
|
||||||
ldr r1, =label
|
ldr r5, =label
|
||||||
adrl r2, label
|
adrl r6, label
|
||||||
label:
|
label:
|
||||||
ASSERT_EQ_REG(r0, r1)
|
ASSERT_EQ_REG(r4, r5)
|
||||||
ASSERT_EQ_REG(r0, r2)
|
ASSERT_EQ_REG(r4, r6)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Error: symbol .data is in a different section.
|
/* Error: symbol .data is in a different section.
|
||||||
@@ -28,6 +28,6 @@ label:
|
|||||||
* If you have no idea what I'm talking about, read this:
|
* If you have no idea what I'm talking about, read this:
|
||||||
* https://stackoverflow.com/questions/3322911/what-do-linkers-do/33690144#33690144
|
* https://stackoverflow.com/questions/3322911/what-do-linkers-do/33690144#33690144
|
||||||
*/
|
*/
|
||||||
adr r1, data_label
|
adr r5, data_label
|
||||||
#endif
|
#endif
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -6,20 +6,37 @@
|
|||||||
.syntax unified
|
.syntax unified
|
||||||
|
|
||||||
/* Assert that a register equals a constant.
|
/* Assert that a register equals a constant.
|
||||||
* * reg: the register to check. Can be r0-r10, but not r11. r11 is overwritten.
|
* * reg: the register to check
|
||||||
* * const: the constant to compare to. Only works for literals or labels, not for registers.
|
* * const: the constant to compare to. Only works for literals or labels, not for registers.
|
||||||
* For register / register comparision, use ASSERT_EQ_REG.
|
* For register / register comparison, use ASSERT_EQ_REG.
|
||||||
*/
|
*/
|
||||||
#define ASSERT_EQ(reg, const) \
|
#define ASSERT_EQ(reg, const) \
|
||||||
ldr r11, =const; \
|
mov r0, reg; \
|
||||||
cmp reg, r11; \
|
ldr r1, =const; \
|
||||||
|
ASSERT_EQ_DO; \
|
||||||
|
;
|
||||||
|
|
||||||
|
#define ASSERT_EQ_DO \
|
||||||
|
bl assert_eq_32; \
|
||||||
|
cmp r0, 0; \
|
||||||
ASSERT(beq); \
|
ASSERT(beq); \
|
||||||
;
|
;
|
||||||
|
|
||||||
|
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||||
|
str reg2, [sp, -4]!; \
|
||||||
|
mov r0, reg1; \
|
||||||
|
ldr r1, [sp], 4; \
|
||||||
|
ASSERT_EQ_DO; \
|
||||||
|
;
|
||||||
|
|
||||||
/* Assert that two arrays are the same. */
|
/* Assert that two arrays are the same. */
|
||||||
#define ASSERT_MEMCMP(s1, s2, n) \
|
#define ASSERT_MEMCMP(label1, label2, const_size) \
|
||||||
MEMCMP(s1, s2, n); \
|
ldr r0, =label1; \
|
||||||
ASSERT_EQ(r0, 0); \
|
ldr r1, =label2; \
|
||||||
|
ldr r2, =const_size; \
|
||||||
|
bl assert_memcmp; \
|
||||||
|
cmp r0, 0; \
|
||||||
|
ASSERT(beq); \
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Store all callee saved registers, and LR in case we make further BL calls.
|
/* Store all callee saved registers, and LR in case we make further BL calls.
|
||||||
|
|||||||
@@ -13,20 +13,20 @@ my_array_1:
|
|||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
|
|
||||||
/* Load r1, r2, r3 and r4 starting from the address in r0. Don't change r0 */
|
/* Load r5, r6, r7 and r8 starting from the address in r4. Don't change r4 */
|
||||||
ldr r0, =my_array_0
|
ldr r4, =my_array_0
|
||||||
ldr r1, =0
|
ldr r5, =0
|
||||||
ldr r2, =0
|
ldr r6, =0
|
||||||
ldr r3, =0
|
ldr r7, =0
|
||||||
ldr r4, =0
|
ldr r8, =0
|
||||||
ldmia r0, {r1-r4}
|
ldmia r4, {r5-r8}
|
||||||
ASSERT_EQ(r0, my_array_0)
|
ASSERT_EQ(r4, my_array_0)
|
||||||
ASSERT_EQ(r1, 0x11111111)
|
ASSERT_EQ(r5, 0x11111111)
|
||||||
ASSERT_EQ(r2, 0x22222222)
|
ASSERT_EQ(r6, 0x22222222)
|
||||||
ASSERT_EQ(r3, 0x33333333)
|
ASSERT_EQ(r7, 0x33333333)
|
||||||
ASSERT_EQ(r4, 0x44444444)
|
ASSERT_EQ(r8, 0x44444444)
|
||||||
|
|
||||||
/* Swapping the order of r1 and r2 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.
|
||||||
*
|
*
|
||||||
* But it gives an assembler warning, so we won't do it by default:
|
* But it gives an assembler warning, so we won't do it by default:
|
||||||
*
|
*
|
||||||
@@ -34,29 +34,28 @@ ENTRY
|
|||||||
* ldmia.S:32: Warning: register range not in ascending order
|
* ldmia.S:32: Warning: register range not in ascending order
|
||||||
*/
|
*/
|
||||||
#if 0
|
#if 0
|
||||||
ldr r0, =my_array_0
|
ldr r4, =my_array_0
|
||||||
ldr r1, =0
|
ldr r5, =0
|
||||||
ldr r2, =0
|
ldr r6, =0
|
||||||
ldmia r0, {r2,r1}
|
ldmia r4, {r6,r5}
|
||||||
ASSERT_EQ(r1, 0x11111111)
|
ASSERT_EQ(r5, 0x11111111)
|
||||||
ASSERT_EQ(r2, 0x22222222)
|
ASSERT_EQ(r6, 0x22222222)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Modify the array */
|
/* Modify the array */
|
||||||
ldr r0, =my_array_1
|
ldr r4, =my_array_1
|
||||||
ldr r1, =0x55555555
|
ldr r5, =0x55555555
|
||||||
ldr r2, =0x66666666
|
ldr r6, =0x66666666
|
||||||
ldr r3, =0x77777777
|
ldr r7, =0x77777777
|
||||||
ldr r4, =0x88888888
|
ldr r8, =0x88888888
|
||||||
stmdb r0, {r1-r4}
|
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. */
|
||||||
MEMCMP(my_array_0, my_array_1, 0x10)
|
ASSERT_MEMCMP(my_array_0, my_array_1, 0x10)
|
||||||
ASSERT_EQ(r0, 0)
|
|
||||||
|
|
||||||
/* Load registers and increment r0. */
|
/* Load registers and increment r4. */
|
||||||
ldr r0, =my_array_0
|
ldr r4, =my_array_0
|
||||||
ldmia r0!, {r1-r4}
|
ldmia r4!, {r5-r8}
|
||||||
ASSERT_EQ(r0, my_array_1)
|
ASSERT_EQ(r4, my_array_1)
|
||||||
|
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -5,27 +5,27 @@
|
|||||||
ENTRY
|
ENTRY
|
||||||
|
|
||||||
/* Save sp before push. */
|
/* Save sp before push. */
|
||||||
mov r0, sp
|
mov r4, sp
|
||||||
|
|
||||||
/* Push. */
|
/* Push. */
|
||||||
mov r1, 1
|
mov r5, 1
|
||||||
mov r2, 2
|
mov r6, 2
|
||||||
push {r1, r2}
|
push {r5, r6}
|
||||||
|
|
||||||
/* Save sp after push. */
|
/* Save sp after push. */
|
||||||
mov r1, sp
|
mov r5, sp
|
||||||
|
|
||||||
/* Restore. */
|
/* Restore. */
|
||||||
mov r3, 0
|
mov r7, 0
|
||||||
mov r4, 0
|
mov r8, 0
|
||||||
pop {r3, r4}
|
pop {r7, r8}
|
||||||
ASSERT_EQ(r3, 1)
|
ASSERT_EQ(r7, 1)
|
||||||
ASSERT_EQ(r4, 2)
|
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 r0, r1
|
sub r4, r5
|
||||||
ASSERT_EQ(r0, 8)
|
ASSERT_EQ(r4, 8)
|
||||||
|
|
||||||
EXIT
|
EXIT
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ myvar:
|
|||||||
.word 0x12345678
|
.word 0x12345678
|
||||||
|
|
||||||
ENTRY
|
ENTRY
|
||||||
/* r0 will contain the address. */
|
|
||||||
ldr r0, =myvar
|
|
||||||
|
|
||||||
/* Sanity check. */
|
/* Sanity check. */
|
||||||
|
ldr r0, =myvar
|
||||||
ldr r1, [r0]
|
ldr r1, [r0]
|
||||||
movw r2, 0x5678
|
movw r2, 0x5678
|
||||||
movt r2, 0x1234
|
movt r2, 0x1234
|
||||||
ASSERT_EQ_REG(r1, r2)
|
ASSERT_EQ_REG(r1, r2)
|
||||||
|
|
||||||
/* Modify the value. */
|
/* Modify the value. */
|
||||||
|
ldr r0, =myvar
|
||||||
movw r1, 0xDEF0
|
movw r1, 0xDEF0
|
||||||
movt r1, 0x9ABC
|
movt r1, 0x9ABC
|
||||||
str r1, [r0]
|
str r1, [r0]
|
||||||
|
|
||||||
/* Check that it changed. */
|
/* Check that it changed. */
|
||||||
|
ldr r0, =myvar
|
||||||
ldr r1, [r0]
|
ldr r1, [r0]
|
||||||
movw r2, 0xDEF0
|
movw r2, 0xDEF0
|
||||||
movt r2, 0x9ABC
|
movt r2, 0x9ABC
|
||||||
|
|||||||
@@ -21,10 +21,12 @@
|
|||||||
1: \
|
1: \
|
||||||
;
|
;
|
||||||
|
|
||||||
|
#ifndef ASSERT_EQ_REG
|
||||||
/* Assert that a register equals another register. */
|
/* Assert that a register equals another register. */
|
||||||
#define ASSERT_EQ_REG(reg1, reg2) \
|
#define ASSERT_EQ_REG(reg1, reg2) \
|
||||||
cmp reg1, reg2; \
|
cmp reg1, reg2; \
|
||||||
ASSERT(beq); \
|
ASSERT(beq); \
|
||||||
;
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,11 +9,53 @@
|
|||||||
|
|
||||||
int asm_main(uint32_t *line);
|
int asm_main(uint32_t *line);
|
||||||
|
|
||||||
|
#define ASSERT_EQ_DEFINE(bits) \
|
||||||
|
int 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)
|
||||||
|
|
||||||
|
int 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) {
|
int main(void) {
|
||||||
uint32_t ret, line;
|
uint32_t ret, line;
|
||||||
ret = asm_main(&line);
|
ret = asm_main(&line);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("error %d at line %d\n", ret, line);
|
printf("error: asm_main returned %d at line %d\n", ret, line);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user