aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Collet <Cyan4973@users.noreply.github.com>2022-08-10 10:57:54 -0700
committerGitHub <noreply@github.com>2022-08-10 10:57:54 -0700
commit70b1201c5b185e2e6f82da4ceffcd5c8ad9b56a3 (patch)
tree38c60a570a71e8a3ea1d8871d6ad4952a54206b9
parentca26930a91e5b1d47d725b1043e1f5282fd18aaf (diff)
parentd0928a7f2071b9f06a32780d79c0c5a0b204c360 (diff)
downloadlz4-70b1201c5b185e2e6f82da4ceffcd5c8ad9b56a3.tar.gz
Merge pull request #1130 from t-mat/freestanding
Add LZ4_FREESTANDING
-rw-r--r--.github/workflows/ci.yml66
-rw-r--r--Makefile4
-rw-r--r--lib/lz4.c4
-rw-r--r--lib/lz4.h30
-rw-r--r--lib/lz4hc.c2
-rw-r--r--lib/lz4hc.h4
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile11
-rw-r--r--tests/freestanding.c239
9 files changed, 328 insertions, 33 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3101d4f8..f27b99a5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,42 +25,44 @@ jobs:
include: [
# You can access the following values via ${{ matrix.??? }}
#
- # pkgs : apt-get package names. It can include multiple package names which are delimited by space.
- # cc : C compiler executable.
- # cxx : C++ compiler executable for `make ctocpptest`.
- # x32 : Set 'true' if compiler supports x32. Otherwise, set 'false'.
- # Set 'fail' if it supports x32 but fails for now. 'fail' cases must be removed.
- # x86 : Set 'true' if compiler supports x86 (-m32). Otherwise, set 'false'.
- # Set 'fail' if it supports x86 but fails for now. 'fail' cases must be removed.
- # cxxtest : Set 'true' if it can be compiled as C++ code. Otherwise, set 'false'.
- # os : GitHub Actions YAML workflow label. See https://github.com/actions/virtual-environments#available-environments
+ # pkgs : apt-get package names. It can include multiple package names which are delimited by space.
+ # cc : C compiler executable.
+ # cxx : C++ compiler executable for `make ctocpptest`.
+ # x32 : Set 'true' if compiler supports x32. Otherwise, set 'false'.
+ # Set 'fail' if it supports x32 but fails for now. 'fail' cases must be removed.
+ # x86 : Set 'true' if compiler supports x86 (-m32). Otherwise, set 'false'.
+ # Set 'fail' if it supports x86 but fails for now. 'fail' cases must be removed.
+ # cxxtest : Set 'true' if it can be compiled as C++ code. Otherwise, set 'false'.
+ # freestanding : Set 'true' if it can be compiled and execute freestanding code. Otherwise, set 'false'.
+ # Usually, it requires Linux, x86_64 and gcc/g++.
+ # os : GitHub Actions YAML workflow label. See https://github.com/actions/virtual-environments#available-environments
# cc
- { pkgs: '', cc: cc, cxx: c++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, },
+ { pkgs: '', cc: cc, cxx: c++, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-latest, },
# gcc
- { pkgs: '', cc: gcc, cxx: g++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, },
- { pkgs: 'gcc-11 g++-11 lib32gcc-11-dev libx32gcc-11-dev', cc: gcc-11, cxx: g++-11, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'gcc-10 lib32gcc-10-dev libx32gcc-10-dev', cc: gcc-10, cxx: g++-10, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'gcc-9 lib32gcc-9-dev libx32gcc-9-dev', cc: gcc-9, cxx: g++-9, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'gcc-8 g++-8 lib32gcc-8-dev libx32gcc-8-dev', cc: gcc-8, cxx: g++-8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'gcc-7 g++-7 lib32gcc-7-dev libx32gcc-7-dev', cc: gcc-7, cxx: g++-7, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'gcc-6 g++-6 lib32gcc-6-dev libx32gcc-6-dev', cc: gcc-6, cxx: g++-6, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, },
- { pkgs: 'gcc-5 g++-5 lib32gcc-5-dev libx32gcc-5-dev', cc: gcc-5, cxx: g++-5, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, },
- { pkgs: 'gcc-4.8 g++-4.8 lib32gcc-4.8-dev libx32gcc-4.8-dev', cc: gcc-4.8, cxx: g++-4.8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, },
+ { pkgs: '', cc: gcc, cxx: g++, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-latest, },
+ { pkgs: 'gcc-11 g++-11 lib32gcc-11-dev libx32gcc-11-dev', cc: gcc-11, cxx: g++-11, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-20.04, },
+ { pkgs: 'gcc-10 lib32gcc-10-dev libx32gcc-10-dev', cc: gcc-10, cxx: g++-10, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-20.04, },
+ { pkgs: 'gcc-9 lib32gcc-9-dev libx32gcc-9-dev', cc: gcc-9, cxx: g++-9, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-20.04, },
+ { pkgs: 'gcc-8 g++-8 lib32gcc-8-dev libx32gcc-8-dev', cc: gcc-8, cxx: g++-8, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-20.04, },
+ { pkgs: 'gcc-7 g++-7 lib32gcc-7-dev libx32gcc-7-dev', cc: gcc-7, cxx: g++-7, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-20.04, },
+ { pkgs: 'gcc-6 g++-6 lib32gcc-6-dev libx32gcc-6-dev', cc: gcc-6, cxx: g++-6, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-18.04, },
+ { pkgs: 'gcc-5 g++-5 lib32gcc-5-dev libx32gcc-5-dev', cc: gcc-5, cxx: g++-5, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-18.04, },
+ { pkgs: 'gcc-4.8 g++-4.8 lib32gcc-4.8-dev libx32gcc-4.8-dev', cc: gcc-4.8, cxx: g++-4.8, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'true', os: ubuntu-18.04, },
# clang
- { pkgs: 'lib32gcc-11-dev libx32gcc-11-dev', cc: clang, cxx: clang++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, },
- { pkgs: 'clang-12 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-12, cxx: clang++-12, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-11 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-11, cxx: clang++-11, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-10 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-10, cxx: clang++-10, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-9 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-9, cxx: clang++-9, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-8 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-8, cxx: clang++-8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-7 lib32gcc-7-dev libx32gcc-7-dev', cc: clang-7, cxx: clang++-7, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-6.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-6.0, cxx: clang++-6.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, },
- { pkgs: 'clang-5.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-5.0, cxx: clang++-5.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, },
- { pkgs: 'clang-4.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-4.0, cxx: clang++-4.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, },
- { pkgs: 'clang-3.9', cc: clang-3.9, cxx: clang++-3.9, x32: 'fail', x86: 'fail', cxxtest: 'false', os: ubuntu-18.04, },
+ { pkgs: 'lib32gcc-11-dev libx32gcc-11-dev', cc: clang, cxx: clang++, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-latest, },
+ { pkgs: 'clang-12 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-12, cxx: clang++-12, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-11 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-11, cxx: clang++-11, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-10 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-10, cxx: clang++-10, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-9 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-9, cxx: clang++-9, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-8 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-8, cxx: clang++-8, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-7 lib32gcc-7-dev libx32gcc-7-dev', cc: clang-7, cxx: clang++-7, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-6.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-6.0, cxx: clang++-6.0, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-20.04, },
+ { pkgs: 'clang-5.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-5.0, cxx: clang++-5.0, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-18.04, },
+ { pkgs: 'clang-4.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-4.0, cxx: clang++-4.0, x32: 'true', x86: 'true', cxxtest: 'true', freestanding: 'false', os: ubuntu-18.04, },
+ { pkgs: 'clang-3.9', cc: clang-3.9, cxx: clang++-3.9, x32: 'fail', x86: 'fail', cxxtest: 'false', freestanding: 'false', os: ubuntu-18.04, },
]
runs-on: ${{ matrix.os }}
@@ -111,6 +113,10 @@ jobs:
if: ${{ matrix.cxxtest == 'true' }}
run: make V=1 clean cxxtest
+ - name: make test-freestanding
+ if: ${{ matrix.freestanding == 'true' }}
+ run: make V=1 clean test-freestanding
+
- name: make -C programs default
if: always()
run: make V=1 -C programs clean default
diff --git a/Makefile b/Makefile
index 9e12ae77..e70c3dbd 100644
--- a/Makefile
+++ b/Makefile
@@ -190,6 +190,10 @@ platformTest: clean
versionsTest: clean
$(MAKE) -C $(TESTDIR) $@
+.PHONY: test-freestanding
+test-freestanding:
+ $(MAKE) -C $(TESTDIR) clean $@
+
.PHONY: cxxtest cxx32test
cxxtest cxx32test: CC := "$(CXX) -Wno-deprecated"
cxxtest cxx32test: CFLAGS = -O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror
diff --git a/lib/lz4.c b/lib/lz4.c
index 5fae0029..ad12281f 100644
--- a/lib/lz4.c
+++ b/lib/lz4.c
@@ -209,7 +209,9 @@ void LZ4_free(void* p);
# define FREEMEM(p) free(p)
#endif
-#include <string.h> /* memset, memcpy */
+#if ! LZ4_FREESTANDING
+# include <string.h> /* memset, memcpy */
+#endif
#if !defined(LZ4_memset)
# define LZ4_memset(p,v,s) memset((p),(v),(s))
#endif
diff --git a/lib/lz4.h b/lib/lz4.h
index fee8890e..9d93eb1f 100644
--- a/lib/lz4.h
+++ b/lib/lz4.h
@@ -97,6 +97,36 @@ extern "C" {
# define LZ4LIB_API LZ4LIB_VISIBILITY
#endif
+/*! LZ4_FREESTANDING :
+ * When this macro is set to 1, it enables "freestanding mode" that is
+ * suitable for typical freestanding environment which doesn't support
+ * standard C library.
+ *
+ * - LZ4_FREESTANDING is a compile-time switch.
+ * - It requires the following macros to be defined:
+ * LZ4_memcpy, LZ4_memmove, LZ4_memset.
+ * - It only enables LZ4/HC functions which don't use heap.
+ * All LZ4F_* functions are not supported.
+ * - See tests/freestanding.c to check its basic setup.
+ */
+#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1)
+# define LZ4_HEAPMODE 0
+# define LZ4HC_HEAPMODE 0
+# define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1
+# if !defined(LZ4_memcpy)
+# error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'."
+# endif
+# if !defined(LZ4_memset)
+# error "LZ4_FREESTANDING requires macro 'LZ4_memset'."
+# endif
+# if !defined(LZ4_memmove)
+# error "LZ4_FREESTANDING requires macro 'LZ4_memmove'."
+# endif
+#elif ! defined(LZ4_FREESTANDING)
+# define LZ4_FREESTANDING 0
+#endif
+
+
/*------ Version ------*/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
diff --git a/lib/lz4hc.c b/lib/lz4hc.c
index 4771ef8f..b21ad6bb 100644
--- a/lib/lz4hc.c
+++ b/lib/lz4hc.c
@@ -1225,6 +1225,7 @@ int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
return 0;
}
+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
void* LZ4_createHC (const char* inputBuffer)
{
LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();
@@ -1239,6 +1240,7 @@ int LZ4_freeHC (void* LZ4HC_Data)
FREEMEM(LZ4HC_Data);
return 0;
}
+#endif
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)
{
diff --git a/lib/lz4hc.h b/lib/lz4hc.h
index d2e51934..e937acfe 100644
--- a/lib/lz4hc.h
+++ b/lib/lz4hc.h
@@ -270,9 +270,11 @@ LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_comp
* LZ4_slideInputBufferHC() will truncate the history of the stream, rather
* than preserve a window-sized chunk of history.
*/
+#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer);
-LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") LZ4LIB_API int LZ4_freeHC (void* LZ4HC_Data);
+#endif
+LZ4_DEPRECATED("use LZ4_saveDictHC() instead") LZ4LIB_API char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") LZ4LIB_API int LZ4_sizeofStreamStateHC(void);
diff --git a/tests/.gitignore b/tests/.gitignore
index 5337fdbd..c7d8f19b 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -14,6 +14,7 @@ checkFrame
decompress-partial
decompress-partial-usingDict
abiTest
+freestanding
# test artefacts
tmp*
diff --git a/tests/Makefile b/tests/Makefile
index 4b6ea489..93a5581c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -115,6 +115,9 @@ decompress-partial: lz4.o decompress-partial.c
decompress-partial-usingDict: lz4.o decompress-partial-usingDict.c
$(CC) $(FLAGS) $^ -o $@$(EXT)
+freestanding: freestanding.c
+ $(CC) -ffreestanding -nostdlib $^ -o $@$(EXT)
+
.PHONY: clean
clean:
@$(MAKE) -C $(LZ4DIR) $@ > $(VOID)
@@ -127,7 +130,7 @@ clean:
fasttest$(EXT) roundTripTest$(EXT) \
datagen$(EXT) checkTag$(EXT) \
frameTest$(EXT) decompress-partial$(EXT) \
- abiTest$(EXT) \
+ abiTest$(EXT) freestanding$(EXT) \
lz4_all.c
@$(RM) -rf $(TESTDIR)
@echo Cleaning completed
@@ -606,4 +609,10 @@ test-decompress-partial : decompress-partial decompress-partial-usingDict
@echo "\n ---- test decompress-partial-usingDict ----"
./decompress-partial-usingDict$(EXT)
+test-freestanding: freestanding
+ @echo "\n ---- test freestanding ----"
+ ./freestanding$(EXT)
+ -strace ./freestanding$(EXT)
+ -ltrace ./freestanding$(EXT)
+
endif
diff --git a/tests/freestanding.c b/tests/freestanding.c
new file mode 100644
index 00000000..ceff4c5a
--- /dev/null
+++ b/tests/freestanding.c
@@ -0,0 +1,239 @@
+// 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__)
+EXTERN_C void _start(void) { }
+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