From 2ca0d0b38b60e8d6d49a8959bf674a79e7d16f41 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Tue, 6 Apr 2021 21:39:07 -0700 Subject: Port zlib-ng to the Android platform - Add Soong blueprint - Add CRC32 fixes - Add NDK mappings All changes were based on the Android fork of Chromium zlib. Change-Id: Icf0f00d95e1534a0f5683cce40679916a464cc12 --- .gitignore | 1 - Android.bp | 244 ++++++++++++++++++++++++++++++++++++++++++ MODULE_LICENSE_BSD_LIKE | 0 arch/arm/crc32_acle.c | 40 +++++++ arch/arm/insert_string_acle.c | 42 +++++++- libz.map.txt | 151 ++++++++++++++++++++++++++ zconf.h | 185 ++++++++++++++++++++++++++++++++ 7 files changed, 660 insertions(+), 3 deletions(-) create mode 100644 Android.bp create mode 100644 MODULE_LICENSE_BSD_LIKE create mode 100644 libz.map.txt create mode 100644 zconf.h diff --git a/.gitignore b/.gitignore index bf420e5..82bd204 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ Testing /*.cmake *.stackdump *._h -zconf.h zconf.h.cmakein zconf.h.included zconf-ng.h diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..a8444fb --- /dev/null +++ b/Android.bp @@ -0,0 +1,244 @@ +package { + default_applicable_licenses: ["external_zlib_license"], +} + +license { + name: "external_zlib_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-BSD", + "SPDX-license-identifier-Zlib", + ], + license_text: [ + "LICENSE.md", + ], +} + +srcs_arm = [ + "arch/arm/adler32_neon.c", + "arch/arm/armfeature.c", + "arch/arm/chunkset_neon.c", + "arch/arm/crc32_acle.c", + "arch/arm/insert_string_acle.c", + "arch/arm/slide_neon.c", +] + +// Not all CPUs will support these features, but compatibility is checked at runtime. +cflags_arm = [ + "-DARM_FEATURES", + + // Runtime compatibility checks + "-DARM_AUXV_HAS_CRC32", + "-DARM_AUXV_HAS_NEON", + + // Optional fatures + "-DARM_ACLE_CRC_HASH", + "-DARM_NEON_ADLER32", + "-DARM_NEON_CHUNKSET", + "-DARM_NEON_SLIDEHASH", +] + +// The *device* x86 configuration (with *higher* CPU feature requirements). +srcs_android_x86 = [ + "arch/x86/adler32_avx.c", + "arch/x86/adler32_ssse3.c", + "arch/x86/chunkset_avx.c", + "arch/x86/chunkset_sse.c", + "arch/x86/compare258_avx.c", + "arch/x86/compare258_sse.c", + "arch/x86/crc_folding.c", + "arch/x86/insert_string_sse.c", + "arch/x86/slide_avx.c", + "arch/x86/slide_sse.c", + "arch/x86/x86.c", +] +cflags_android_x86 = [ + "-DX86_AVX2", + "-DX86_AVX2_ADLER32", + "-DX86_AVX_CHUNKSET", + "-DX86_FEATURES", + "-DX86_PCLMULQDQ_CRC", + "-DX86_SSE2", + "-DX86_SSE2_CHUNKSET", + "-DX86_SSE2_SLIDEHASH", + "-DX86_SSE42_CMP_STR", + "-DX86_SSE42_CRC_HASH", + "-DX86_SSE42_CRC_INTRIN", + "-DX86_SSSE3", + "-DX86_SSSE3_ADLER32", + "-mavx2", + "-msse4", + "-mssse3", + "-mpclmul", +] + +// This optimization is applicable to arm64 and x86-64. +cflags_64 = ["-DUNALIGNED64_OK"] + +libz_srcs = [ + "adler32.c", + "chunkset.c", + "compare258.c", + "compress.c", + "crc32_comb.c", + "crc32.c", + "deflate_fast.c", + "deflate_medium.c", + "deflate_quick.c", + "deflate_slow.c", + "deflate.c", + "functable.c", + "gzlib.c", + "gzread.c", + "gzwrite.c", + "infback.c", + "inffast.c", + "inflate.c", + "inftrees.c", + "insert_string.c", + "trees.c", + "uncompr.c", + "zutil.c", +] + +cflags_common = [ + "-DHAVE_BUILTIN_CTZ", + "-DHAVE_BUILTIN_CTZLL", + "-DHAVE_VISIBILITY_HIDDEN", + "-DHAVE_VISIBILITY_INTERNAL", + "-DZLIB_CONST", + + "-DWITH_GZFILEOP", + "-DZLIB_COMPAT", + "-DZLIB_DLL", + "-D_LARGEFILE64_SOURCE=1", + "-D__USE_LARGEFILE64", + "-Wall", + "-Werror", + "-Wno-implicit-fallthrough", + "-O3", + "-DNDEBUG", + "-fno-semantic-interposition", + "-std=c99", + "-DUNALIGNED_OK", +] + +cc_defaults { + name: "libz_defaults", + + cflags: cflags_common, + stl: "none", + export_include_dirs: ["."], + srcs: libz_srcs, + + arch: { + arm: { + // TODO: This is to work around b/24465209. Remove after root cause + // is fixed. + pack_relocations: false, + ldflags: ["-Wl,--hash-style=both"], + + cflags: cflags_arm, + srcs: srcs_arm, + }, + arm64: { + cflags: cflags_arm + cflags_64, + srcs: srcs_arm, + }, + x86_64: { + cflags: cflags_64, + }, + }, + target: { + android_x86: { + srcs: srcs_android_x86, + cflags: cflags_android_x86, + }, + android_x86_64: { + srcs: srcs_android_x86, + cflags: cflags_android_x86 + cflags_64, + }, + }, +} + +cc_library { + name: "libz", + defaults: ["libz_defaults"], + + host_supported: true, + unique_host_soname: true, + static_ndk_lib: true, + + vendor_available: true, + product_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, + ramdisk_available: true, + vendor_ramdisk_available: true, + recovery_available: true, + native_bridge_supported: true, + + target: { + linux_bionic: { + enabled: true, + }, + windows: { + enabled: true, + }, + }, + + stubs: { + versions: [ + "29", + "30", + ], + symbol_file: "libz.map.txt", + }, +} + +// A more stable build of libz. Build configuration of this library should be +// the same for different targets. This is only used by imgdiff. + +cc_library { + name: "libz_stable", + visibility: [ + "//bootable/recovery/applypatch", + "//bootable/recovery/tests", + ], + cflags: cflags_common, + stl: "none", + export_include_dirs: ["."], + srcs: libz_srcs, + + host_supported: true, + vendor_available: true, + recovery_available: true, +} + +cc_binary_host { + name: "minigzip", + srcs: ["test/minigzip.c"], + cflags: cflags_common, + static_libs: ["libz"], + stl: "none", +} + +ndk_headers { + name: "libz_headers", + from: "", + to: "", + srcs: [ + "zconf.h", + "zlib.h", + ], + license: "LICENSE.md", +} + +ndk_library { + name: "libz", + symbol_file: "libz.map.txt", + first_version: "9", + unversioned_until: "current", +} diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 0000000..e69de29 diff --git a/arch/arm/crc32_acle.c b/arch/arm/crc32_acle.c index 88ba6c3..99013e1 100644 --- a/arch/arm/crc32_acle.c +++ b/arch/arm/crc32_acle.c @@ -11,6 +11,46 @@ #endif #include "../../zutil.h" +#if defined(__clang__) +/* CRC32 intrinsics are #ifdef'ed out of arm_acle.h unless we build with an + * armv8 target, which is incompatible with ThinLTO optimizations on Android. + * (Namely, mixing and matching different module-level targets makes ThinLTO + * warn, and Android defaults to armv7-a. This restriction does not apply to + * function-level `target`s, however.) + * + * Since we only need four crc intrinsics, and since clang's implementation of + * those are just wrappers around compiler builtins, it's simplest to #define + * those builtins directly. If this #define list grows too much (or we depend on + * an intrinsic that isn't a trivial wrapper), we may have to find a better way + * to go about this. + * + * NOTE: clang currently complains that "'+soft-float-abi' is not a recognized + * feature for this target (ignoring feature)." This appears to be a harmless + * bug in clang. + */ +#define __crc32b __builtin_arm_crc32b +#define __crc32d __builtin_arm_crc32d +#define __crc32w __builtin_arm_crc32w +#define __crc32cw __builtin_arm_crc32cw +#define __crc32h __builtin_arm_crc32h + +#if defined(__aarch64__) +#define TARGET_ARMV8_WITH_CRC __attribute__((target("crc"))) +#else // !defined(__aarch64__) +#define TARGET_ARMV8_WITH_CRC __attribute__((target("armv8-a,crc"))) +#endif // defined(__aarch64__) + +#elif defined(__GNUC__) +/* For GCC, we are setting CRC extensions at module level, so ThinLTO is not + * allowed. We can just include arm_acle.h. + */ +#include +#define TARGET_ARMV8_WITH_CRC +#else // !defined(__GNUC__) && !defined(_aarch64__) +#error ARM CRC32 SIMD extensions only supported for Clang and GCC +#endif + +TARGET_ARMV8_WITH_CRC uint32_t crc32_acle(uint32_t crc, const unsigned char *buf, uint64_t len) { Z_REGISTER uint32_t c; Z_REGISTER const uint16_t *buf2; diff --git a/arch/arm/insert_string_acle.c b/arch/arm/insert_string_acle.c index 2daf9ba..4fd5fa7 100644 --- a/arch/arm/insert_string_acle.c +++ b/arch/arm/insert_string_acle.c @@ -12,11 +12,49 @@ #include "../../zbuild.h" #include "../../deflate.h" +#if defined(__clang__) +/* CRC32 intrinsics are #ifdef'ed out of arm_acle.h unless we build with an + * armv8 target, which is incompatible with ThinLTO optimizations on Android. + * (Namely, mixing and matching different module-level targets makes ThinLTO + * warn, and Android defaults to armv7-a. This restriction does not apply to + * function-level `target`s, however.) + * + * Since we only need four crc intrinsics, and since clang's implementation of + * those are just wrappers around compiler builtins, it's simplest to #define + * those builtins directly. If this #define list grows too much (or we depend on + * an intrinsic that isn't a trivial wrapper), we may have to find a better way + * to go about this. + * + * NOTE: clang currently complains that "'+soft-float-abi' is not a recognized + * feature for this target (ignoring feature)." This appears to be a harmless + * bug in clang. + */ +#define __crc32b __builtin_arm_crc32b +#define __crc32d __builtin_arm_crc32d +#define __crc32w __builtin_arm_crc32w +#define __crc32cw __builtin_arm_crc32cw + +#if defined(__aarch64__) +#define TARGET_ARMV8_WITH_CRC __attribute__((target("crc"))) +#else // !defined(__aarch64__) +#define TARGET_ARMV8_WITH_CRC __attribute__((target("armv8-a,crc"))) +#endif // defined(__aarch64__) + +#elif defined(__GNUC__) +/* For GCC, we are setting CRC extensions at module level, so ThinLTO is not + * allowed. We can just include arm_acle.h. + */ +#include +#define TARGET_ARMV8_WITH_CRC +#else // !defined(__GNUC__) && !defined(_aarch64__) +#error ARM CRC32 SIMD extensions only supported for Clang and GCC +#endif + #define UPDATE_HASH(s, h, val) \ h = __crc32w(0, val) -#define INSERT_STRING insert_string_acle -#define QUICK_INSERT_STRING quick_insert_string_acle +#define INSERT_STRING TARGET_ARMV8_WITH_CRC insert_string_acle +#define QUICK_INSERT_STRING TARGET_ARMV8_WITH_CRC quick_insert_string_acle #include "../../insert_string_tpl.h" #endif diff --git a/libz.map.txt b/libz.map.txt new file mode 100644 index 0000000..850bbf8 --- /dev/null +++ b/libz.map.txt @@ -0,0 +1,151 @@ +# This file is copied from src/zlib.map and annotated with comments for the NDK +# stub library generation script. +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; # var + inflate_copyright; # var + inflate_fast; + inflate_table; + zcalloc; + zcfree; + z_errmsg; # var + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; + +ZLIB_1.2.5.1 { + deflatePending; +} ZLIB_1.2.3.5; + +ZLIB_1.2.5.2 { + deflateResetKeep; + gzgetc_; + inflateResetKeep; +} ZLIB_1.2.5.1; + +ZLIB_1.2.7.1 { # introduced=19 + inflateGetDictionary; + gzvprintf; +} ZLIB_1.2.5.2; + +ZLIB_1.2.9 { # introduced=28 + inflateCodesUsed; + inflateValidate; + uncompress2; + gzfread; + gzfwrite; + deflateGetDictionary; + adler32_z; + crc32_z; +} ZLIB_1.2.7.1; + +# These were all exposed by the old NDK stub library. Unclear if they still +# should be, but at least some of them are marked as being exported in zlib.h +# and the tree doesn't build without them. +ZLIB_NDK { + _dist_code; + _length_code; + _tr_align; + _tr_flush_bits; # introduced=21 + _tr_flush_block; + _tr_init; + _tr_stored_block; + _tr_tally; + adler32; + compress2; + compress; + crc32; + deflate; + deflateCopy; + deflateEnd; + deflateInit2_; + deflateInit_; + deflateParams; + deflateReset; + deflateSetDictionary; + get_crc_table; + gzclose; + gzdopen; + gzeof; + gzerror; + gzflush; + gzgetc; + gzgets; + gzopen; + gzprintf; + gzputc; + gzputs; + gzread; + gzrewind; + gzseek; + gzsetparams; + gztell; + gzwrite; + inflate; + inflateEnd; + inflateInit2_; + inflateInit_; + inflateReset; + inflateSetDictionary; + inflateSync; + inflateSyncPoint; + uncompress; + zError; + zlibVersion; +}; diff --git a/zconf.h b/zconf.h new file mode 100644 index 0000000..58255ed --- /dev/null +++ b/zconf.h @@ -0,0 +1,185 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef ZCONF_H +#define ZCONF_H + +#if !defined(_WIN32) && defined(__WIN32__) +# define _WIN32 +#endif + +#ifdef __STDC_VERSION__ +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif + +/* Clang macro for detecting declspec support + * https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute + */ +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(x) 0 +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# define MAX_MEM_LEVEL 9 +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + +/* Type declarations */ + + +#ifndef OF /* function prototypes */ +# define OF(args) args +#endif + +#ifdef ZLIB_INTERNAL +# define Z_INTERNAL ZLIB_INTERNAL +#endif + +/* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +#if defined(ZLIB_DLL) && (defined(_WIN32) || (__has_declspec_attribute(dllexport) && __has_declspec_attribute(dllimport))) +# ifdef Z_INTERNAL +# define Z_EXTERN extern __declspec(dllexport) +# else +# define Z_EXTERN extern __declspec(dllimport) +# endif +#endif + +/* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +#if defined(ZLIB_WINAPI) && defined(_WIN32) +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define Z_EXPORT WINAPI +# define Z_EXPORTVA WINAPIV +#endif + +#ifndef Z_EXTERN +# define Z_EXTERN extern +#endif +#ifndef Z_EXPORT +# define Z_EXPORT +#endif +#ifndef Z_EXPORTVA +# define Z_EXPORTVA +#endif + +/* Fallback for something that includes us. */ +typedef unsigned char Byte; +typedef Byte Bytef; + +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +typedef char charf; +typedef int intf; +typedef uInt uIntf; +typedef uLong uLongf; + +typedef void const *voidpc; +typedef void *voidpf; +typedef void *voidp; + +#if 1 /* was set to #if 1 by configure/cmake/etc */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef NEED_PTRDIFF_T /* may be set to #if 1 by configure/cmake/etc */ +typedef PTRDIFF_TYPE ptrdiff_t; +#endif + +#include /* for off_t */ +#include /* for va_list */ + +#include /* for wchar_t and NULL */ + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifndef z_off_t +# define z_off_t off_t +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(__MSYS__) +# define z_off64_t _off64_t +# elif defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +#endif /* ZCONF_H */ -- cgit v1.2.3