From f176d04500112bb18034dc655f741404838df02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Sun, 5 May 2019 00:00:00 +0000 Subject: [PATCH] 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 --- userland/arch/aarch64/common_arch.h | 63 ++++++++++++++++++----------- userland/arch/aarch64/cset.S | 32 +++++++-------- userland/arch/aarch64/ret.S | 14 +++---- userland/arch/aarch64/ubfm.S | 14 +++---- userland/arch/aarch64/ubfx.S | 14 +++---- userland/arch/aarch64/x31.S | 26 ++++++------ userland/arch/arm/address_modes.S | 60 +++++++++++++-------------- userland/arch/arm/adr.S | 12 +++--- userland/arch/arm/common_arch.h | 31 ++++++++++---- userland/arch/arm/ldmia.S | 61 ++++++++++++++-------------- userland/arch/arm/push.S | 24 +++++------ userland/arch/arm/str.S | 6 +-- userland/arch/common.h | 2 + userland/arch/main.c | 44 +++++++++++++++++++- 14 files changed, 240 insertions(+), 163 deletions(-) diff --git a/userland/arch/aarch64/common_arch.h b/userland/arch/aarch64/common_arch.h index f14d96e..9f70dc4 100644 --- a/userland/arch/aarch64/common_arch.h +++ b/userland/arch/aarch64/common_arch.h @@ -4,31 +4,55 @@ #define COMMON_ARCH_H #define ASSERT_EQ(reg, const) \ - ldr x11, =const; \ - cmp reg, x11; \ + mov x0, reg; \ + ldr x1, =const; \ + ASSERT_EQ_DO(64); \ +; + +#define ASSERT_EQ_DO(bits) \ + bl assert_eq_ ## bits; \ + cmp x0, 0; \ ASSERT(beq); \ ; -#define ASSERT_MEMCMP(s1, s2, n) \ - MEMCMP(s1, s2, n); \ - ASSERT_EQ(x0, 0); \ +#define ASSERT_EQ_REG(reg1, reg2) \ + str reg2, [sp, -8]!; \ + 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 \ .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]; \ + 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: \ ; @@ -56,11 +80,4 @@ pass: \ b fail; \ ; -#define MEMCMP(s1, s2, n) \ - adr x0, s1; \ - adr x1, s2; \ - ldr x2, =n; \ - bl memcmp; \ -; - #endif diff --git a/userland/arch/aarch64/cset.S b/userland/arch/aarch64/cset.S index 0213183..d252387 100644 --- a/userland/arch/aarch64/cset.S +++ b/userland/arch/aarch64/cset.S @@ -4,25 +4,25 @@ ENTRY /* Test values. */ - mov x0, 0 - mov x1, 1 + mov x19, 0 + mov x20, 1 - /* eq is true, set x2 = 1. */ - cmp x0, x0 - cset x2, eq - ASSERT_EQ(x2, 1) + /* eq is true, set x21 = 1. */ + cmp x19, x19 + cset x21, eq + ASSERT_EQ(x21, 1) - /* eq is false, set x2 = 0. */ - cmp x0, x1 - cset x2, eq - ASSERT_EQ(x2, 0) + /* eq is false, set x21 = 0. */ + cmp x19, x20 + cset x21, eq + ASSERT_EQ(x21, 0) /* Same for ne. */ - cmp x0, x0 - cset x2, ne - ASSERT_EQ(x2, 0) + cmp x19, x19 + cset x21, ne + ASSERT_EQ(x21, 0) - cmp x0, x1 - cset x2, ne - ASSERT_EQ(x2, 1) + cmp x19, x20 + cset x21, ne + ASSERT_EQ(x21, 1) EXIT diff --git a/userland/arch/aarch64/ret.S b/userland/arch/aarch64/ret.S index ab77e24..adb1cda 100644 --- a/userland/arch/aarch64/ret.S +++ b/userland/arch/aarch64/ret.S @@ -3,26 +3,26 @@ #include "common.h" ENTRY - mov x0, 1 + mov x19, 1 bl inc - ASSERT_EQ(x0, 2) + ASSERT_EQ(x19, 2) bl inc2 - ASSERT_EQ(x0, 3) + ASSERT_EQ(x19, 3) bl inc3 - ASSERT_EQ(x0, 4) + ASSERT_EQ(x19, 4) EXIT /* void inc(uint64_t *i) { (*i)++ } */ inc: - add x0, x0, 1 + add x19, x19, 1 ret /* Same but explicit return register. */ inc2: - add x0, x0, 1 + add x19, x19, 1 ret x30 /* Same but with br. */ inc3: - add x0, x0, 1 + add x19, x19, 1 br x30 diff --git a/userland/arch/aarch64/ubfm.S b/userland/arch/aarch64/ubfm.S index 4821f7a..da03a8d 100644 --- a/userland/arch/aarch64/ubfm.S +++ b/userland/arch/aarch64/ubfm.S @@ -3,15 +3,15 @@ #include "common.h" ENTRY - ldr x0, =0x1122334455667788 + ldr x19, =0x1122334455667788 // lsr alias: imms == 63 - ldr x1, =0xFFFFFFFFFFFFFFFF - ubfm x1, x0, 16, 63 - ASSERT_EQ(x1, 0x0000112233445566) + ldr x20, =0xFFFFFFFFFFFFFFFF + ubfm x20, x19, 16, 63 + ASSERT_EQ(x20, 0x0000112233445566) - ldr x1, =0xFFFFFFFFFFFFFFFF - ubfm x1, x0, 32, 63 - ASSERT_EQ(x1, 0x0000000011223344) + ldr x20, =0xFFFFFFFFFFFFFFFF + ubfm x20, x19, 32, 63 + ASSERT_EQ(x20, 0x0000000011223344) EXIT diff --git a/userland/arch/aarch64/ubfx.S b/userland/arch/aarch64/ubfx.S index 7a1735b..b9a2c93 100644 --- a/userland/arch/aarch64/ubfx.S +++ b/userland/arch/aarch64/ubfx.S @@ -3,13 +3,13 @@ #include "common.h" ENTRY - ldr x0, =0x1122334455667788 + ldr x19, =0x1122334455667788 - ldr x1, =0xFFFFFFFFFFFFFFFF - ubfx x1, x0, 8, 16 - ASSERT_EQ(x1, 0x0000000000006677) + ldr x20, =0xFFFFFFFFFFFFFFFF + ubfx x20, x19, 8, 16 + ASSERT_EQ(x20, 0x0000000000006677) - ldr x1, =0xFFFFFFFFFFFFFFFF - ubfx x1, x0, 8, 32 - ASSERT_EQ(x1, 0x0000000044556677) + ldr x20, =0xFFFFFFFFFFFFFFFF + ubfx x20, x19, 8, 32 + ASSERT_EQ(x20, 0x0000000044556677) EXIT diff --git a/userland/arch/aarch64/x31.S b/userland/arch/aarch64/x31.S index c53f148..a54d6dc 100644 --- a/userland/arch/aarch64/x31.S +++ b/userland/arch/aarch64/x31.S @@ -9,14 +9,14 @@ ENTRY #endif /* mov (register) is an alias for ORR, which accepts xzr. */ - mov x0, 1 - mov x0, xzr - ASSERT_EQ(x0, 0) + mov x19, 1 + mov x19, xzr + ASSERT_EQ(x19, 0) /* Same encoding as the mov version. */ - mov x0, 1 - orr x0, xzr, xzr - ASSERT_EQ(x0, 0) + mov x19, 1 + orr x19, xzr, xzr + ASSERT_EQ(x19, 0) /* So, orr, which is not an alias, can only take xzr, not sp. */ #if 0 @@ -24,19 +24,19 @@ ENTRY #endif /* Zero register discards result if written to. */ - mov x0, 1 - orr xzr, x0, x0 + mov x19, 1 + orr xzr, x19, x19 ASSERT_EQ(xzr, 0) /* MOV (to/from SP) is an alias for ADD (immediate). */ - mov x0, sp + mov x19, sp mov sp, 1 /* Alias to add. */ - mov x1, sp + mov x20, sp /* Exact same encoding as above. */ - add x1, sp, 0 - ASSERT_EQ(x1, 1) - mov sp, x0 + add x20, sp, 0 + mov sp, x19 + ASSERT_EQ(x20, 1) /* So, ADD (immediate), which is not an alias, can only take sp, not xzr. */ #if 0 diff --git a/userland/arch/arm/address_modes.S b/userland/arch/arm/address_modes.S index d263d9d..c3d2750 100644 --- a/userland/arch/arm/address_modes.S +++ b/userland/arch/arm/address_modes.S @@ -4,48 +4,48 @@ ENTRY - /* Offset mode with immediate. Add 4 to the address register, which ends up - * reading myvar2 instead of myvar. + /* Offset mode with immediate. Add 4 to the address register, + * which ends up * reading myvar6 instead of myvar. */ - adr r0, myvar - ldr r1, [r0, 4] - ASSERT_EQ(r1, 0x9ABCDEF0) - /* r0 was not modified. */ - ASSERT_EQ(r0, myvar) + adr r4, myvar + ldr r5, [r4, 4] + ASSERT_EQ(r5, 0x9ABCDEF0) + /* r4 was not modified. */ + ASSERT_EQ(r4, myvar) - /* Pre-indexed mode */ - adr r0, myvar - ldr r1, [r0, 4]! - ASSERT_EQ(r1, 0x9ABCDEF0) - /* r0 was modified. */ - ASSERT_EQ(r0, myvar2) + /* Pre-indexed mode: modify register, then use it. */ + adr r4, myvar + ldr r5, [r4, 4]! + ASSERT_EQ(r5, 0x9ABCDEF0) + /* r4 was modified. */ + ASSERT_EQ(r4, myvar6) - /* Post-indexed mode */ - adr r0, myvar - ldr r1, [r0], 4 - ASSERT_EQ(r1, 0x12345678) - /* r0 was modified. */ - ASSERT_EQ(r0, myvar2) + /* Post-indexed mode: use register, then modify it. */ + adr r4, myvar + ldr r5, [r4], 4 + ASSERT_EQ(r5, 0x12345678) + /* r4 was modified. */ + ASSERT_EQ(r4, myvar6) /* Offset in register. */ - adr r0, myvar - mov r1, 4 - ldr r2, [r0, r1] - ASSERT_EQ(r2, 0x9ABCDEF0) + adr r4, myvar + mov r5, 4 + ldr r6, [r4, r5] + ASSERT_EQ(r6, 0x9ABCDEF0) /* Offset in shifted register: - * r2 = - * (r0 + (r1 << 1)) + * r6 = + * (r4 + (r5 << 1)) * == *(myvar + (2 << 1)) * == *(myvar + 4) */ - adr r0, myvar - mov r1, 2 - ldr r2, [r0, r1, lsl 1] - ASSERT_EQ(r2, 0x9ABCDEF0) + adr r4, myvar + mov r5, 2 + ldr r6, [r4, r5, lsl 1] + ASSERT_EQ(r6, 0x9ABCDEF0) EXIT myvar: .word 0x12345678 -myvar2: +myvar6: .word 0x9ABCDEF0 diff --git a/userland/arch/arm/adr.S b/userland/arch/arm/adr.S index 69862a8..6fe9e1a 100644 --- a/userland/arch/arm/adr.S +++ b/userland/arch/arm/adr.S @@ -6,16 +6,16 @@ data_label: .word 0x1234678 ENTRY - adr r0, label + adr r4, label /* objdump tells us that this uses the literal pool, * it does not get converted to adr, which is the better * alternative here. */ - ldr r1, =label - adrl r2, label + ldr r5, =label + adrl r6, label label: - ASSERT_EQ_REG(r0, r1) - ASSERT_EQ_REG(r0, r2) + ASSERT_EQ_REG(r4, r5) + ASSERT_EQ_REG(r4, r6) #if 0 /* 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: * https://stackoverflow.com/questions/3322911/what-do-linkers-do/33690144#33690144 */ - adr r1, data_label + adr r5, data_label #endif EXIT diff --git a/userland/arch/arm/common_arch.h b/userland/arch/arm/common_arch.h index e019916..ab65b3a 100644 --- a/userland/arch/arm/common_arch.h +++ b/userland/arch/arm/common_arch.h @@ -6,20 +6,37 @@ .syntax unified /* 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. - * For register / register comparision, use ASSERT_EQ_REG. + * For register / register comparison, use ASSERT_EQ_REG. */ #define ASSERT_EQ(reg, const) \ - ldr r11, =const; \ - cmp reg, r11; \ + mov r0, reg; \ + ldr r1, =const; \ + ASSERT_EQ_DO; \ +; + +#define ASSERT_EQ_DO \ + bl assert_eq_32; \ + cmp r0, 0; \ 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. */ -#define ASSERT_MEMCMP(s1, s2, n) \ - MEMCMP(s1, s2, n); \ - ASSERT_EQ(r0, 0); \ +#define ASSERT_MEMCMP(label1, label2, const_size) \ + ldr r0, =label1; \ + 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. diff --git a/userland/arch/arm/ldmia.S b/userland/arch/arm/ldmia.S index 3f0c38f..6665dce 100644 --- a/userland/arch/arm/ldmia.S +++ b/userland/arch/arm/ldmia.S @@ -13,20 +13,20 @@ my_array_1: ENTRY - /* Load r1, r2, r3 and r4 starting from the address in r0. Don't change r0 */ - ldr r0, =my_array_0 - ldr r1, =0 - ldr r2, =0 - ldr r3, =0 - ldr r4, =0 - ldmia r0, {r1-r4} - ASSERT_EQ(r0, my_array_0) - ASSERT_EQ(r1, 0x11111111) - ASSERT_EQ(r2, 0x22222222) - ASSERT_EQ(r3, 0x33333333) - ASSERT_EQ(r4, 0x44444444) + /* Load r5, r6, r7 and r8 starting from the address in r4. Don't change r4 */ + ldr r4, =my_array_0 + ldr r5, =0 + ldr r6, =0 + 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) - /* 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: * @@ -34,29 +34,28 @@ ENTRY * ldmia.S:32: Warning: register range not in ascending order */ #if 0 - ldr r0, =my_array_0 - ldr r1, =0 - ldr r2, =0 - ldmia r0, {r2,r1} - ASSERT_EQ(r1, 0x11111111) - ASSERT_EQ(r2, 0x22222222) + ldr r4, =my_array_0 + ldr r5, =0 + ldr r6, =0 + ldmia r4, {r6,r5} + ASSERT_EQ(r5, 0x11111111) + ASSERT_EQ(r6, 0x22222222) #endif /* Modify the array */ - ldr r0, =my_array_1 - ldr r1, =0x55555555 - ldr r2, =0x66666666 - ldr r3, =0x77777777 - ldr r4, =0x88888888 - stmdb r0, {r1-r4} + ldr r4, =my_array_1 + ldr r5, =0x55555555 + ldr r6, =0x66666666 + ldr r7, =0x77777777 + ldr r8, =0x88888888 + stmdb r4, {r5-r8} /* Verify that my_array_0 changed and is equal to my_array_1. */ - MEMCMP(my_array_0, my_array_1, 0x10) - ASSERT_EQ(r0, 0) + ASSERT_MEMCMP(my_array_0, my_array_1, 0x10) - /* Load registers and increment r0. */ - ldr r0, =my_array_0 - ldmia r0!, {r1-r4} - ASSERT_EQ(r0, my_array_1) + /* Load registers and increment r4. */ + ldr r4, =my_array_0 + ldmia r4!, {r5-r8} + ASSERT_EQ(r4, my_array_1) EXIT diff --git a/userland/arch/arm/push.S b/userland/arch/arm/push.S index d336a7d..08bb839 100644 --- a/userland/arch/arm/push.S +++ b/userland/arch/arm/push.S @@ -5,27 +5,27 @@ ENTRY /* Save sp before push. */ - mov r0, sp + mov r4, sp /* Push. */ - mov r1, 1 - mov r2, 2 - push {r1, r2} + mov r5, 1 + mov r6, 2 + push {r5, r6} /* Save sp after push. */ - mov r1, sp + mov r5, sp /* Restore. */ - mov r3, 0 - mov r4, 0 - pop {r3, r4} - ASSERT_EQ(r3, 1) - ASSERT_EQ(r4, 2) + mov r7, 0 + mov r8, 0 + pop {r7, r8} + ASSERT_EQ(r7, 1) + ASSERT_EQ(r8, 2) /* Check that stack pointer moved down by 8 bytes * (2 registers x 4 bytes each). */ - sub r0, r1 - ASSERT_EQ(r0, 8) + sub r4, r5 + ASSERT_EQ(r4, 8) EXIT diff --git a/userland/arch/arm/str.S b/userland/arch/arm/str.S index 0543292..64f3c33 100644 --- a/userland/arch/arm/str.S +++ b/userland/arch/arm/str.S @@ -8,21 +8,21 @@ myvar: .word 0x12345678 ENTRY - /* r0 will contain the address. */ - ldr r0, =myvar - /* Sanity check. */ + ldr r0, =myvar ldr r1, [r0] movw r2, 0x5678 movt r2, 0x1234 ASSERT_EQ_REG(r1, r2) /* Modify the value. */ + ldr r0, =myvar movw r1, 0xDEF0 movt r1, 0x9ABC str r1, [r0] /* Check that it changed. */ + ldr r0, =myvar ldr r1, [r0] movw r2, 0xDEF0 movt r2, 0x9ABC diff --git a/userland/arch/common.h b/userland/arch/common.h index 2ad672e..d6812ec 100644 --- a/userland/arch/common.h +++ b/userland/arch/common.h @@ -21,10 +21,12 @@ 1: \ ; +#ifndef ASSERT_EQ_REG /* Assert that a register equals another register. */ #define ASSERT_EQ_REG(reg1, reg2) \ cmp reg1, reg2; \ ASSERT(beq); \ ; +#endif #endif diff --git a/userland/arch/main.c b/userland/arch/main.c index ae5354c..7e51702 100644 --- a/userland/arch/main.c +++ b/userland/arch/main.c @@ -9,11 +9,53 @@ 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) { uint32_t ret, line; ret = asm_main(&line); 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; }