• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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