// Basic test for LZ4_FREESTANDING // $ gcc -ffreestanding -nostdlib freestanding.c && ./a.out || echo $? // $ strace ./a.out // execve("./a.out", ["./a.out"], 0x7fffaf5fa580 /* 22 vars */) = 0 // brk(NULL) = 0x56536f4fe000 // arch_prctl(0x3001 /* ARCH_??? */, 0x7fffc9e74950) = -1 EINVAL (Invalid argument) // mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd5c9c2b000 // access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) // arch_prctl(ARCH_SET_FS, 0x7fd5c9c2bc40) = 0 // set_tid_address(0x7fd5c9c2bf10) = 381 // set_robust_list(0x7fd5c9c2bf20, 24) = 0 // rseq(0x7fd5c9c2c5e0, 0x20, 0, 0x53053053) = 0 // mprotect(0x56536ea63000, 4096, PROT_READ) = 0 // exit(0) = ? // +++ exited with 0 +++ // $ ltrace ./a.out // +++ exited (status 0) +++ #include #include #if defined(__cplusplus) # define EXTERN_C extern "C" #else # define EXTERN_C #endif #if !defined(__x86_64__) || !defined(__linux__) int main(int argc, char** argv) { return 0; } #else static void MY_exit(int exitCode); static void MY_abort(void); EXTERN_C void *memmove(void *dst, const void *src, size_t n); EXTERN_C void *memcpy(void * __restrict__ dst, const void * __restrict__ src, size_t n); EXTERN_C void *memset(void *s, int c, size_t n); EXTERN_C int memcmp(const void *s1, const void *s2, size_t n); // LZ4/HC basic freestanding setup #define LZ4_FREESTANDING 1 #define LZ4_memmove(dst, src, size) memmove((dst),(src),(size)) #define LZ4_memcpy(dst, src, size) memcpy((dst),(src),(size)) #define LZ4_memset(p,v,s) memset((p),(v),(s)) #include "../lib/lz4.c" #include "../lib/lz4hc.c" // Test for LZ4 static void test_lz4(const uint8_t* srcData, int srcSize) { // Compress static uint8_t compressBuffer[1024 * 1024]; const int compressedSize = LZ4_compress_default( (const char*) srcData, (char*) compressBuffer, srcSize, sizeof(compressBuffer) ); if (compressedSize <= 0) { MY_exit(__LINE__); } // Decompress static uint8_t decompressBuffer[1024 * 1024]; const int decompressedSize = LZ4_decompress_safe( (const char*) compressBuffer, (char*) decompressBuffer, compressedSize, sizeof(decompressBuffer) ); if (decompressedSize <= 0) { MY_exit(__LINE__); } // Verify if (decompressedSize != srcSize) { MY_exit(__LINE__); } if (memcmp(srcData, decompressBuffer, srcSize) != 0) { MY_exit(__LINE__); } } // Test for LZ4HC static void test_lz4hc(const uint8_t* srcData, int srcSize) { // Compress static uint8_t compressBuffer[1024 * 1024]; const int compressedSize = LZ4_compress_HC( (const char*) srcData, (char*) compressBuffer, srcSize, sizeof(compressBuffer), LZ4HC_CLEVEL_DEFAULT ); if (compressedSize <= 0) { MY_exit(__LINE__); } // Decompress static uint8_t decompressBuffer[1024 * 1024]; const int decompressedSize = LZ4_decompress_safe( (const char*) compressBuffer, (char*) decompressBuffer, compressedSize, sizeof(decompressBuffer) ); if (decompressedSize <= 0) { MY_exit(__LINE__); } // Verify if (decompressedSize != srcSize) { MY_exit(__LINE__); } if (memcmp(srcData, decompressBuffer, srcSize) != 0) { MY_exit(__LINE__); } } static void test(void) { // First 256 bytes of lz4/README.md static const uint8_t README_md[] = { 0x4c, 0x5a, 0x34, 0x20, 0x2d, 0x20, 0x45, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x6c, 0x79, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x0a, 0x0a, 0x4c, 0x5a, 0x34, 0x20, 0x69, 0x73, 0x20, 0x6c, 0x6f, 0x73, 0x73, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2c, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x3e, 0x20, 0x35, 0x30, 0x30, 0x20, 0x4d, 0x42, 0x2f, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x2c, 0x0a, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x43, 0x50, 0x55, 0x2e, 0x0a, 0x49, 0x74, 0x20, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x6c, 0x79, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2c, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x47, 0x42, 0x2f, 0x73, 0x20, 0x70, 0x65, 0x72, }; static const uint8_t* srcData = README_md; static const int srcSize = (int) sizeof(README_md); test_lz4 (srcData, srcSize); test_lz4hc(srcData, srcSize); } // low level syscall #define SYS_exit (60) static __inline long os_syscall1(long n, long a1) { register long rax __asm__ ("rax") = n; register long rdi __asm__ ("rdi") = a1; __asm__ __volatile__ ("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory"); return rax; } static void MY_exit(int exitCode) { (void) os_syscall1(SYS_exit, exitCode); __builtin_unreachable(); // suppress "warning: 'noreturn' function does return" } static void MY_abort(void) { MY_exit(-1); } // https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---assert-fail-1.html void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) { MY_abort(); } // GCC requires memcpy, memmove, memset and memcmp. // https://gcc.gnu.org/onlinedocs/gcc/Standards.html // > GCC requires the freestanding environment provide memcpy, memmove, memset and memcmp. EXTERN_C void *memmove(void *dst, const void *src, size_t n) { uint8_t* d = (uint8_t*) dst; const uint8_t* s = (const uint8_t*) src; if (d > s) { d += n; s += n; while (n--) { *--d = *--s; } } else { while (n--) { *d++ = *s++; } } return dst; } EXTERN_C void *memcpy(void * __restrict__ dst, const void * __restrict__ src, size_t n) { return memmove(dst, src, n); } EXTERN_C void *memset(void *s, int c, size_t n) { uint8_t* p = (uint8_t*) s; while (n--) { *p++ = (uint8_t) c; } return s; } EXTERN_C int memcmp(const void *s1, const void *s2, size_t n) { const uint8_t* p1 = (const uint8_t*) s1; const uint8_t* p2 = (const uint8_t*) s2; while (n--) { const uint8_t c1 = *p1++; const uint8_t c2 = *p2++; if (c1 < c2) { return -1; } else if (c1 > c2) { return 1; } } return 0; } // EXTERN_C void _start(void) { test(); MY_exit(0); } int main(int argc, char** argv) { test(); MY_exit(0); return 0; } #endif