mirror of
https://github.com/lz4/lz4.git
synced 2024-11-27 03:48:08 +08:00
08f1483b0a
Freestanding test is intended to run on only Linux x86_64 platform. Because it uses Linux x86_64 syscall directly to avoid any dependency to the standard library. This changeset adds platform checking code to tests/Makefile to avoid unintended error in non-Linux x86_64 platforms. This changeset resolves issue #1186
239 lines
7.4 KiB
C
239 lines
7.4 KiB
C
// 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 <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#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
|