1 // Basic test for LZ4_FREESTANDING
2
3 // $ gcc -ffreestanding -nostdlib freestanding.c && ./a.out || echo $?
4
5 // $ strace ./a.out
6 // execve("./a.out", ["./a.out"], 0x7fffaf5fa580 /* 22 vars */) = 0
7 // brk(NULL) = 0x56536f4fe000
8 // arch_prctl(0x3001 /* ARCH_??? */, 0x7fffc9e74950) = -1 EINVAL (Invalid argument)
9 // mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd5c9c2b000
10 // access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
11 // arch_prctl(ARCH_SET_FS, 0x7fd5c9c2bc40) = 0
12 // set_tid_address(0x7fd5c9c2bf10) = 381
13 // set_robust_list(0x7fd5c9c2bf20, 24) = 0
14 // rseq(0x7fd5c9c2c5e0, 0x20, 0, 0x53053053) = 0
15 // mprotect(0x56536ea63000, 4096, PROT_READ) = 0
16 // exit(0) = ?
17 // +++ exited with 0 +++
18
19 // $ ltrace ./a.out
20 // +++ exited (status 0) +++
21
22 #include <stddef.h>
23 #include <stdint.h>
24
25 #if defined(__cplusplus)
26 # define EXTERN_C extern "C"
27 #else
28 # define EXTERN_C
29 #endif
30
31
32 #if !defined(__x86_64__) || !defined(__linux__)
_start(void)33 EXTERN_C void _start(void) { }
main(int argc,char ** argv)34 int main(int argc, char** argv) { return 0; }
35 #else
36
37 static void MY_exit(int exitCode);
38 static void MY_abort(void);
39 EXTERN_C void *memmove(void *dst, const void *src, size_t n);
40 EXTERN_C void *memcpy(void * __restrict__ dst, const void * __restrict__ src, size_t n);
41 EXTERN_C void *memset(void *s, int c, size_t n);
42 EXTERN_C int memcmp(const void *s1, const void *s2, size_t n);
43
44 // LZ4/HC basic freestanding setup
45 #define LZ4_FREESTANDING 1
46 #define LZ4_memmove(dst, src, size) memmove((dst),(src),(size))
47 #define LZ4_memcpy(dst, src, size) memcpy((dst),(src),(size))
48 #define LZ4_memset(p,v,s) memset((p),(v),(s))
49
50 #include "../lib/lz4.c"
51 #include "../lib/lz4hc.c"
52
53 // Test for LZ4
test_lz4(const uint8_t * srcData,int srcSize)54 static void test_lz4(const uint8_t* srcData, int srcSize) {
55 // Compress
56 static uint8_t compressBuffer[1024 * 1024];
57 const int compressedSize = LZ4_compress_default(
58 (const char*) srcData,
59 (char*) compressBuffer,
60 srcSize,
61 sizeof(compressBuffer)
62 );
63 if (compressedSize <= 0) {
64 MY_exit(__LINE__);
65 }
66
67 // Decompress
68 static uint8_t decompressBuffer[1024 * 1024];
69 const int decompressedSize = LZ4_decompress_safe(
70 (const char*) compressBuffer,
71 (char*) decompressBuffer,
72 compressedSize,
73 sizeof(decompressBuffer)
74 );
75 if (decompressedSize <= 0) {
76 MY_exit(__LINE__);
77 }
78
79 // Verify
80 if (decompressedSize != srcSize) {
81 MY_exit(__LINE__);
82 }
83 if (memcmp(srcData, decompressBuffer, srcSize) != 0) {
84 MY_exit(__LINE__);
85 }
86 }
87
88
89 // Test for LZ4HC
test_lz4hc(const uint8_t * srcData,int srcSize)90 static void test_lz4hc(const uint8_t* srcData, int srcSize) {
91 // Compress
92 static uint8_t compressBuffer[1024 * 1024];
93 const int compressedSize = LZ4_compress_HC(
94 (const char*) srcData,
95 (char*) compressBuffer,
96 srcSize,
97 sizeof(compressBuffer),
98 LZ4HC_CLEVEL_DEFAULT
99 );
100 if (compressedSize <= 0) {
101 MY_exit(__LINE__);
102 }
103
104 // Decompress
105 static uint8_t decompressBuffer[1024 * 1024];
106 const int decompressedSize = LZ4_decompress_safe(
107 (const char*) compressBuffer,
108 (char*) decompressBuffer,
109 compressedSize,
110 sizeof(decompressBuffer)
111 );
112 if (decompressedSize <= 0) {
113 MY_exit(__LINE__);
114 }
115
116 // Verify
117 if (decompressedSize != srcSize) {
118 MY_exit(__LINE__);
119 }
120 if (memcmp(srcData, decompressBuffer, srcSize) != 0) {
121 MY_exit(__LINE__);
122 }
123 }
124
125
test(void)126 static void test(void) {
127 // First 256 bytes of lz4/README.md
128 static const uint8_t README_md[] = {
129 0x4c, 0x5a, 0x34, 0x20, 0x2d, 0x20, 0x45, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x6c, 0x79, 0x20,
130 0x66, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
131 0x0a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
132 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
133 0x3d, 0x0a, 0x0a, 0x4c, 0x5a, 0x34, 0x20, 0x69, 0x73, 0x20, 0x6c, 0x6f, 0x73, 0x73, 0x6c, 0x65,
134 0x73, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61,
135 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2c, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
136 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20,
137 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x3e, 0x20, 0x35, 0x30, 0x30, 0x20, 0x4d, 0x42, 0x2f, 0x73,
138 0x20, 0x70, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x2c, 0x0a, 0x73, 0x63, 0x61, 0x6c, 0x61,
139 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x63,
140 0x6f, 0x72, 0x65, 0x73, 0x20, 0x43, 0x50, 0x55, 0x2e, 0x0a, 0x49, 0x74, 0x20, 0x66, 0x65, 0x61,
141 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65,
142 0x6c, 0x79, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2c,
143 0x0a, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x70, 0x65, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6d,
144 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x47, 0x42, 0x2f, 0x73, 0x20, 0x70, 0x65, 0x72,
145 };
146
147 static const uint8_t* srcData = README_md;
148 static const int srcSize = (int) sizeof(README_md);
149 test_lz4 (srcData, srcSize);
150 test_lz4hc(srcData, srcSize);
151 }
152
153
154 // low level syscall
155 #define SYS_exit (60)
156
os_syscall1(long n,long a1)157 static __inline long os_syscall1(long n, long a1) {
158 register long rax __asm__ ("rax") = n;
159 register long rdi __asm__ ("rdi") = a1;
160 __asm__ __volatile__ ("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
161 return rax;
162 }
163
MY_exit(int exitCode)164 static void MY_exit(int exitCode) {
165 (void) os_syscall1(SYS_exit, exitCode);
166 __builtin_unreachable(); // suppress "warning: 'noreturn' function does return"
167 }
168
MY_abort(void)169 static void MY_abort(void) {
170 MY_exit(-1);
171 }
172
173 // https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---assert-fail-1.html
__assert_fail(const char * assertion,const char * file,unsigned int line,const char * function)174 void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) {
175 MY_abort();
176 }
177
178
179 // GCC requires memcpy, memmove, memset and memcmp.
180 // https://gcc.gnu.org/onlinedocs/gcc/Standards.html
181 // > GCC requires the freestanding environment provide memcpy, memmove, memset and memcmp.
memmove(void * dst,const void * src,size_t n)182 EXTERN_C void *memmove(void *dst, const void *src, size_t n) {
183 uint8_t* d = (uint8_t*) dst;
184 const uint8_t* s = (const uint8_t*) src;
185
186 if (d > s) {
187 d += n;
188 s += n;
189 while (n--) {
190 *--d = *--s;
191 }
192 } else {
193 while (n--) {
194 *d++ = *s++;
195 }
196 }
197 return dst;
198 }
199
memcpy(void * __restrict__ dst,const void * __restrict__ src,size_t n)200 EXTERN_C void *memcpy(void * __restrict__ dst, const void * __restrict__ src, size_t n) {
201 return memmove(dst, src, n);
202 }
203
memset(void * s,int c,size_t n)204 EXTERN_C void *memset(void *s, int c, size_t n) {
205 uint8_t* p = (uint8_t*) s;
206 while (n--) {
207 *p++ = (uint8_t) c;
208 }
209 return s;
210 }
211
memcmp(const void * s1,const void * s2,size_t n)212 EXTERN_C int memcmp(const void *s1, const void *s2, size_t n) {
213 const uint8_t* p1 = (const uint8_t*) s1;
214 const uint8_t* p2 = (const uint8_t*) s2;
215 while (n--) {
216 const uint8_t c1 = *p1++;
217 const uint8_t c2 = *p2++;
218 if (c1 < c2) {
219 return -1;
220 } else if (c1 > c2) {
221 return 1;
222 }
223 }
224 return 0;
225 }
226
227
228 //
_start(void)229 EXTERN_C void _start(void) {
230 test();
231 MY_exit(0);
232 }
233
main(int argc,char ** argv)234 int main(int argc, char** argv) {
235 test();
236 MY_exit(0);
237 return 0;
238 }
239 #endif
240