Skip to content

Commit

Permalink
lib: add freestanding support
Browse files Browse the repository at this point in the history
Allow building libdeflate without linking to any libc functions by using
'make FREESTANDING=1'.  When using such a library build, the user will
need to call libdeflate_set_memory_allocator() before anything else,
since malloc() and free() will be unavailable.

[Folded in fix from Ingvar Stepanyan to use -nostdlib, and made
 freestanding_tests() check that no libs are linked to.]

Update #62
  • Loading branch information
ebiggers committed Apr 18, 2020
1 parent 0ded4c6 commit 27d5a74
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ matrix:
- sudo apt-get install -y libz-dev gcc-multilib libz-dev:i386
libc6-dev-i386 valgrind clang gcc-4.8-multilib gcc-mingw-w64-i686
script:
- tools/run_tests.sh native
- tools/run_tests.sh native freestanding

- name: Checksum, static analysis, and edge case tests (Linux)
os: linux
Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
# Define DESTDIR to override the installation destination directory
# (default: empty string)
#
# Define FREESTANDING to build a freestanding library, i.e. a library that
# doesn't link to any libc functions like malloc(), free(), and memcpy().
# All users will need to call libdeflate_set_memory_allocator().
#
# You can also specify custom CFLAGS, CPPFLAGS, and/or LDFLAGS.
#
##############################################################################
Expand All @@ -50,7 +54,11 @@ override CFLAGS := \
$(call cc-option,-Wvla) \
$(call cc-option,-Wimplicit-fallthrough)

# We don't define any CPPFLAGS, but support the user specifying it.
FREESTANDING :=
ifdef FREESTANDING
override CPPFLAGS += -DFREESTANDING
LIB_CFLAGS += -ffreestanding -nostdlib
endif

##############################################################################

Expand Down
4 changes: 3 additions & 1 deletion lib/arm/cpu_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include "../lib_common.h"

#if (defined(__arm__) || defined(__aarch64__)) && \
defined(__linux__) && COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE
defined(__linux__) && \
COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \
!defined(FREESTANDING)
# define ARM_CPU_FEATURES_ENABLED 1
#else
# define ARM_CPU_FEATURES_ENABLED 0
Expand Down
2 changes: 0 additions & 2 deletions lib/deflate_compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/

#include <string.h>

#include "deflate_compress.h"
#include "deflate_constants.h"
#include "unaligned.h"
Expand Down
1 change: 0 additions & 1 deletion lib/deflate_decompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
*/

#include <limits.h>
#include <string.h>

#include "deflate_constants.h"
#include "unaligned.h"
Expand Down
9 changes: 9 additions & 0 deletions lib/lib_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,13 @@ void libdeflate_free(void *ptr);
void *libdeflate_aligned_malloc(size_t alignment, size_t size);
void libdeflate_aligned_free(void *ptr);

#ifdef FREESTANDING
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
#else
#include <string.h>
#endif

#endif /* LIB_LIB_COMMON_H */
61 changes: 60 additions & 1 deletion lib/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/

#include <stdlib.h>
#ifdef FREESTANDING
# define malloc NULL
# define free NULL
#else
# include <stdlib.h>
#endif

#include "lib_common.h"

Expand Down Expand Up @@ -72,3 +77,57 @@ libdeflate_set_memory_allocator(void *(*malloc_func)(size_t),
libdeflate_malloc_func = malloc_func;
libdeflate_free_func = free_func;
}

/*
* Implementations of libc functions for freestanding library builds.
* Not optimized yet. Normal library builds don't use these.
*/
#ifdef FREESTANDING
void *memset(void *s, int c, size_t n)
{
u8 *p = s;
size_t i;

for (i = 0; i < n; i++)
p[i] = c;
return s;
}

void *memcpy(void *dest, const void *src, size_t n)
{
u8 *d = dest;
const u8 *s = src;
size_t i;

for (i = 0; i < n; i++)
d[i] = s[i];
return dest;
}

void *memmove(void *dest, const void *src, size_t n)
{
u8 *d = dest;
const u8 *s = src;
size_t i;

if (d <= s)
return memcpy(d, s, n);

for (i = n; i > 0; i--)
d[i - 1] = s[i - 1];
return dest;
}

int memcmp(const void *s1, const void *s2, size_t n)
{
const u8 *p1 = s1;
const u8 *p2 = s2;
size_t i;

for (i = 0; i < n; i++) {
if (p1[i] != p2[i])
return (int)p1[i] - (int)p2[i];
}
return 0;
}
#endif /* FREESTANDING */
5 changes: 5 additions & 0 deletions programs/prog_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ void
begin_program(tchar *argv[])
{
program_invocation_name = get_filename(argv[0]);

#ifdef FREESTANDING
/* This allows testing freestanding library builds. */
libdeflate_set_memory_allocator(malloc, free);
#endif
}

/* Create a copy of 'path' surrounded by double quotes */
Expand Down
28 changes: 28 additions & 0 deletions tools/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,33 @@ native_tests() {
fi
}

# Test the library built with FREESTANDING=1.
freestanding_tests() {
test_group_included freestanding || return 0

WRAPPER= native_build_and_test FREESTANDING=1
if nm libdeflate.so | grep ' U ' > "$TMPFILE"; then
echo 1>&2 "Freestanding lib links to external functions!:"
nm libdeflate.so | grep ' U '
return 1
fi
ldd libdeflate.so > "$TMPFILE"
if grep -q -v 'statically linked' "$TMPFILE"; then
echo 1>&2 "Freestanding lib links to external libraries!:"
cat "$TMPFILE"
return 1
fi

if have_valgrind; then
WRAPPER="$VALGRIND" native_build_and_test FREESTANDING=1
fi

if have_ubsan; then
WRAPPER= native_build_and_test FREESTANDING=1 \
CC=clang CFLAGS="$SANITIZE_CFLAGS"
fi
}

###############################################################################

checksum_benchmarks() {
Expand Down Expand Up @@ -361,6 +388,7 @@ log " SMOKEDATA=$SMOKEDATA"
log " NDKDIR=$NDKDIR"

native_tests
freestanding_tests
checksum_benchmarks
android_tests
mips_tests
Expand Down

0 comments on commit 27d5a74

Please sign in to comment.