diff --git a/ld/cryptfx.ld b/ld/cryptfx.ld index 4cb5972..46dcd9b 100644 --- a/ld/cryptfx.ld +++ b/ld/cryptfx.ld @@ -28,5 +28,12 @@ SECTIONS _bdata = . ; *(.data); _edata = . ; + + /* Provide a default */ + _end = . ; } > ram + + /DISCARD/ : { + *(.eh_frame) + } } diff --git a/src/cryptfx.c b/src/cryptfx.c index d350e27..ac349dc 100644 --- a/src/cryptfx.c +++ b/src/cryptfx.c @@ -3,12 +3,14 @@ extern "C" { #endif #include "string.h" - #include "fxlib.h" - + #include "fxlib.h" + #ifdef __cplusplus } #endif +#include "memfunctest.h" + // unused void conv_to_hex(char x, char* a, char* b) { *a = (x >> 4) & 0xf; @@ -34,25 +36,26 @@ int main(void) { //char* out; char out[20] = {0}; - while (1) { - Bdisp_AllClr_DD(); + Bdisp_AllClr_DD(); - locate(1, 1); - Print((unsigned char*) in); + locate(1, 1); + Print((unsigned char*) in); - //out = (char*) malloc(strlen(in) + 1); - strcpy(out, in); - locate(1, 2); - Print((unsigned char*) out); - //free(out); + //out = (char*) malloc(strlen(in) + 1); + strcpy(out, in); + locate(1, 2); + Print((unsigned char*) out); + //free(out); - Bdisp_PutDisp_DD(); - GetKey(&key); - } + locate(1, 3); + memfunctest(); - return 0; + Bdisp_PutDisp_DD(); + while(1) GetKey(&key); + + return 0; } void initialize(void) { main(); -} \ No newline at end of file +} diff --git a/src/memfunctest.c b/src/memfunctest.c new file mode 100644 index 0000000..a40a661 --- /dev/null +++ b/src/memfunctest.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include + +/* 4-abyte buffer alignement */ +#define ALIGN(n) __attribute__((aligned(n))) +/* Unused parameters */ +#define UNUSED __attribute__((unused)) + +//--- +// Basic setup +//--- + +/* Source buffer, used as a data source when copying */ +ALIGN(4) static uint8_t src[256]; +/* Destination buffer, used as destination when copying or clearing */ +ALIGN(4) static uint8_t dst[256]; +/* System buffer, used to reproduce the behavior on the system and compare */ +ALIGN(4) static uint8_t sys[256]; +/* Temporary buffer, used by the naive memmove() */ +ALIGN(4) static uint8_t tmp[256]; + +/* fill() - fill a buffer with non-zero data */ +static void fill(uint8_t *buf) +{ + for(int i = 0; i < 256; i++) buf[i] = i; +} + +/* clear() - clear a buffer with zeros */ +static void clear(uint8_t *buf) +{ + for(int i = 0; i < 256; i++) buf[i] = 0; +} + +/* cmp() - check that some two buffers are equal + Returns non-zero if the buffers differ. */ +static int cmp(uint8_t *lft, uint8_t *rgt) +{ + for(int i = 0; i < 256; i++) if(lft[i] != rgt[i]) return 1; + return 0; +} + +//--- +// Naive functions (reference behaviour) +//--- + +/* naive_memcpy() - bytewise copy */ +static void *naive_memcpy(void *_dst, const void *_src, size_t len) +{ + uint8_t *dst = _dst; + uint8_t const *src = _src; + + while(len--) *dst++ = *src++; + return _dst; +} + +/* naive_memset() - bytewise set */ +static void *naive_memset(void *_dst, int byte, size_t len) +{ + uint8_t *dst = _dst; + + while(len--) *dst++ = byte; + return _dst; +} + +/* naive_memmove() - bytewise copy with buffer */ +static void *naive_memmove(void *_dst, const void *_src, size_t len) +{ + naive_memcpy(tmp, _src, len); + naive_memcpy(_dst, tmp, len); + return _dst; +} + +//--- +// Testing functions +//--- + +static int test_memcpy(int off_dst, int off_src, size_t len) +{ + clear(dst); + clear(sys); + + memcpy(dst + off_dst, src + off_src, len); + naive_memcpy(sys + off_dst, src + off_src, len); + + return cmp(dst, sys); +} + +static int test_memset(int off_dst, UNUSED int off_src, size_t len) +{ + fill(dst); + fill(sys); + + memset(dst + off_dst, 0, len); + naive_memset(sys + off_dst, 0, len); + + return cmp(dst, sys); +} + +static int test_memmove(int off_dst, int off_src, size_t len) +{ + fill(dst); + fill(sys); + + memmove(dst + off_dst, dst + off_src, len); + naive_memmove(sys + off_dst, sys + off_src, len); + + return cmp(dst, sys); +} + +//--- +// Automated tests +// +// These tests are meant to check all size/alignment scenarios for the +// core memory functions. Two intervals of sizes are tested: +// - 12..15 bytes, expected to be handled naively +// - 192..195 bytes, expected to trigger alignment-related optimizations +// For each of these intervals, all alignments possibilities are tested: +// - 4n + { 0,1,2,3 } for the source address +// - 4n + { 0,1,2,3 } for destination address +// Also, the source and destination regions are made to overlap to allow +// non-trivial memmove() cases to be checked. +// +// The testing function non-zero if one or more tests fail. +//--- + +/* test() - check core memory functions in various size/alignment scenarios + + The function to test takes three arguments: two buffer offsets and the size + of the operation. Bounds need no be checked. It must return 0 in case of + success and non-zero in case of failure. + + @func Function to test, will be called with various sizes and alignments + @count If non-null, set to number of tests performed + Returns the number of failed tests; thus, non-zero indicates failure. */ +static int test(int (*func)(int off_dst, int off_src, size_t size), int *count) +{ + /* Number of failed tests */ + int failed = 0; + /* Number of tests */ + int tests = 0; + + /* For each source and destination alignment... */ + for(int dst_al = 0; dst_al < 4; dst_al++) + for(int src_al = 0; src_al < 4; src_al++) + /* For each "alignment" of operation size... */ + for(int len_al = 0; len_al < 4; len_al++) + { + /* Try a small size first */ + failed += !!func(96 + dst_al, 96 + src_al, 12 + len_al); + /* Then a medium region without overlapping */ + failed += !!func(4 + dst_al, 128 + src_al, 92 + len_al); + /* A large region with left-right overlapping */ + failed += !!func(64 + dst_al, 96 + src_al, 128 + len_al); + /* A large region with right-left overlapping */ + failed += !!func(96 + dst_al, 64 + src_al, 128 + len_al); + + tests += 4; + } + + if(count) *count = tests; + return failed; +} + +//--- +// Main function +//--- + +/* memfunctest() - check the bejavior of the core memory functions + Returns non-zero if any test fails. */ +int memfunctest(void) +{ + int count = 0, failed = 0, count_one, failed_one; + fill(src); + + failed_one = test(test_memcpy, &count_one); + failed += failed_one; + count += count_one; + + failed_one = test(test_memset, &count_one); + failed += failed_one; + count += count_one; + + failed_one = test(test_memmove, &count_one); + failed += failed_one; + count += count_one; + + char str[21]; + sprintf(str, "Score: %d/%d.", count - failed, count); + Print(str); + + return (failed != 0); +} diff --git a/src/memfunctest.h b/src/memfunctest.h new file mode 100644 index 0000000..5ee8983 --- /dev/null +++ b/src/memfunctest.h @@ -0,0 +1,17 @@ +//--- +// memfunctest - Check the behaviour of the core memory functions +// +// This small program checks that memcpy(), memset() and memmove() work +// properly in all source/destination alignment, size, overlap scenarios. +// It also checks both small and large areas to trigger usual optimizations. +//--- + +#ifndef __MEMFUNCTEST_H__ +#define __MEMFUNCTEST_H__ + +/* memfunctest() - check the bejavior of the core memory functions + Displays the test result on the screen. + Returns non-zero if any test fails. */ +int memfunctest(void); + +#endif /* __MEMFUNCTEST_H__ */