From: liaohua <liaoh...@huawei.com> We have some questions about xz bcj filters. 1. Why ARM and ARM-Thumb bcj filters are little endian only? 2. Why there is no arm64 bcj filter? Are there any technical risks? Or other considerations?
It notes that ARM bcj filter is little endian only, but we apply ARM bcj filter in big endian architecture(target: arm32 big endian, kernel and rootfs) and works ok too; We only find that there are different code flows to parse “start=offset” option in source codes; We add arm64 bcj filter support in local xz codes and it works ok. We modify the Linux Kernel codes accordingly and use the new xz to compress kernel, and kernel is decompressed successfully during startup. The following is the patch for arm64 bcj filter support which is based on xz 5.2.5 version. Signed-off-by: liaohua <liaoh...@huawei.com> --- CMakeLists.txt | 3 ++ configure.ac | 4 +-- src/liblzma/api/lzma/bcj.h | 4 +++ src/liblzma/common/filter_common.c | 10 +++++- src/liblzma/common/filter_decoder.c | 8 +++++ src/liblzma/common/filter_encoder.c | 10 ++++++ src/liblzma/simple/Makefile.inc | 4 +++ src/liblzma/simple/arm64.c | 72 +++++++++++++++++++++++++++++++++++++ src/liblzma/simple/simple_coder.h | 7 ++++ src/xz/args.c | 7 ++++ src/xz/message.c | 5 ++- 11 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/liblzma/simple/arm64.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 34c6aca..f9d5db9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ add_compile_definitions( HAVE_CHECK_SHA256 HAVE_DECODERS HAVE_DECODER_ARM + HAVE_DECODER_ARM64 HAVE_DECODER_ARMTHUMB HAVE_DECODER_DELTA HAVE_DECODER_IA64 @@ -93,6 +94,7 @@ add_compile_definitions( HAVE_DECODER_X86 HAVE_ENCODERS HAVE_ENCODER_ARM + HAVE_ENCODER_ARM64 HAVE_ENCODER_ARMTHUMB HAVE_ENCODER_DELTA HAVE_ENCODER_IA64 @@ -315,6 +317,7 @@ add_library(liblzma src/liblzma/rangecoder/range_decoder.h src/liblzma/rangecoder/range_encoder.h src/liblzma/simple/arm.c + src/liblzma/simple/arm64.c src/liblzma/simple/armthumb.c src/liblzma/simple/ia64.c src/liblzma/simple/powerpc.c diff --git a/configure.ac b/configure.ac index 5d288b9..3e51444 100644 --- a/configure.ac +++ b/configure.ac @@ -79,8 +79,8 @@ fi # Filters # ########### -m4_define([SUPPORTED_FILTERS], [lzma1,lzma2,delta,x86,powerpc,ia64,arm,armthumb,sparc])dnl -m4_define([SIMPLE_FILTERS], [x86,powerpc,ia64,arm,armthumb,sparc]) +m4_define([SUPPORTED_FILTERS], [lzma1,lzma2,delta,x86,powerpc,ia64,arm,arm64,armthumb,sparc])dnl +m4_define([SIMPLE_FILTERS], [x86,powerpc,ia64,arm,arm64,armthumb,sparc]) m4_define([LZ_FILTERS], [lzma1,lzma2]) m4_foreach([NAME], [SUPPORTED_FILTERS], diff --git a/src/liblzma/api/lzma/bcj.h b/src/liblzma/api/lzma/bcj.h index 8e37538..d0a2094 100644 --- a/src/liblzma/api/lzma/bcj.h +++ b/src/liblzma/api/lzma/bcj.h @@ -49,6 +49,10 @@ * Filter for SPARC binaries. */ +#define LZMA_FILTER_ARM64 LZMA_VLI_C(0x0a) + /**< + * Filter for ARM64 binaries. + */ /** * \brief Options for BCJ filters diff --git a/src/liblzma/common/filter_common.c b/src/liblzma/common/filter_common.c index 9ad5d5d..dea53e1 100644 --- a/src/liblzma/common/filter_common.c +++ b/src/liblzma/common/filter_common.c @@ -12,7 +12,6 @@ #include "filter_common.h" - static const struct { /// Filter ID lzma_vli id; @@ -88,6 +87,15 @@ static const struct { .changes_size = false, }, #endif +#if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64) + { + .id = LZMA_FILTER_ARM64, + .options_size = sizeof(lzma_options_bcj), + .non_last_ok = true, + .last_ok = false, + .changes_size = false, + }, +#endif #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB) { .id = LZMA_FILTER_ARMTHUMB, diff --git a/src/liblzma/common/filter_decoder.c b/src/liblzma/common/filter_decoder.c index c75b0a8..6d0f577 100644 --- a/src/liblzma/common/filter_decoder.c +++ b/src/liblzma/common/filter_decoder.c @@ -91,6 +91,14 @@ static const lzma_filter_decoder decoders[] = { .props_decode = &lzma_simple_props_decode, }, #endif +#ifdef HAVE_DECODER_ARM64 + { + .id = LZMA_FILTER_ARM64, + .init = &lzma_simple_arm64_decoder_init, + .memusage = NULL, + .props_decode = &lzma_simple_props_decode, + }, +#endif #ifdef HAVE_DECODER_ARMTHUMB { .id = LZMA_FILTER_ARMTHUMB, diff --git a/src/liblzma/common/filter_encoder.c b/src/liblzma/common/filter_encoder.c index c5d8f39..4a9b747 100644 --- a/src/liblzma/common/filter_encoder.c +++ b/src/liblzma/common/filter_encoder.c @@ -116,6 +116,16 @@ static const lzma_filter_encoder encoders[] = { .props_encode = &lzma_simple_props_encode, }, #endif +#ifdef HAVE_ENCODER_ARM64 + { + .id = LZMA_FILTER_ARM64, + .init = &lzma_simple_arm64_encoder_init, + .memusage = NULL, + .block_size = NULL, + .props_size_get = &lzma_simple_props_size, + .props_encode = &lzma_simple_props_encode, + }, +#endif #ifdef HAVE_ENCODER_ARMTHUMB { .id = LZMA_FILTER_ARMTHUMB, diff --git a/src/liblzma/simple/Makefile.inc b/src/liblzma/simple/Makefile.inc index 8a5e2d7..3e1f41d 100644 --- a/src/liblzma/simple/Makefile.inc +++ b/src/liblzma/simple/Makefile.inc @@ -38,6 +38,10 @@ if COND_FILTER_ARM liblzma_la_SOURCES += simple/arm.c endif +if COND_FILTER_ARM64 +liblzma_la_SOURCES += simple/arm64.c +endif + if COND_FILTER_ARMTHUMB liblzma_la_SOURCES += simple/armthumb.c endif diff --git a/src/liblzma/simple/arm64.c b/src/liblzma/simple/arm64.c new file mode 100644 index 0000000..6147897 --- /dev/null +++ b/src/liblzma/simple/arm64.c @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \file arm64.c +/// \brief Filter for ARM64 binaries +/// +// Authors: Igor Pavlov +// Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "simple_private.h" + + +static size_t +arm64_code(void *simple lzma_attribute((__unused__)), + uint32_t now_pos, bool is_encoder, + uint8_t *buffer, size_t size) +{ + size_t i; + for (i = 0; i + 4 <= size; i += 4) { + // arm64 bl instruction: 0x94 and 0x97; + if (buffer[i + 3] == 0x94 || buffer[i + 3] == 0x97) { + uint32_t src = ((uint32_t)(buffer[i + 2]) << 16) + | ((uint32_t)(buffer[i + 1]) << 8) + | (uint32_t)(buffer[i + 0]); + src <<= 2; + + uint32_t dest; + if (is_encoder) + dest = now_pos + (uint32_t)(i) + src; + else + dest = src - (now_pos + (uint32_t)(i)); + + dest >>= 2; + buffer[i + 2] = (dest >> 16); + buffer[i + 1] = (dest >> 8); + buffer[i + 0] = dest; + } + } + + return i; +} + + +static lzma_ret +arm64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, + const lzma_filter_info *filters, bool is_encoder) +{ + return lzma_simple_coder_init(next, allocator, filters, + &arm64_code, 0, 4, 4, is_encoder); +} + + +extern lzma_ret +lzma_simple_arm64_encoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, + const lzma_filter_info *filters) +{ + return arm64_coder_init(next, allocator, filters, true); +} + + +extern lzma_ret +lzma_simple_arm64_decoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, + const lzma_filter_info *filters) +{ + return arm64_coder_init(next, allocator, filters, false); +} diff --git a/src/liblzma/simple/simple_coder.h b/src/liblzma/simple/simple_coder.h index 19c2ee0..4d150f6 100644 --- a/src/liblzma/simple/simple_coder.h +++ b/src/liblzma/simple/simple_coder.h @@ -51,6 +51,13 @@ extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, const lzma_filter_info *filters); +extern lzma_ret lzma_simple_arm64_encoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, + const lzma_filter_info *filters); + +extern lzma_ret lzma_simple_arm64_decoder_init(lzma_next_coder *next, + const lzma_allocator *allocator, + const lzma_filter_info *filters); extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, diff --git a/src/xz/args.c b/src/xz/args.c index 9238fb3..cf6a2d2 100644 --- a/src/xz/args.c +++ b/src/xz/args.c @@ -124,6 +124,7 @@ parse_real(args_info *args, int argc, char **argv) OPT_POWERPC, OPT_IA64, OPT_ARM, + OPT_ARM64, OPT_ARMTHUMB, OPT_SPARC, OPT_DELTA, @@ -193,6 +194,7 @@ parse_real(args_info *args, int argc, char **argv) { "powerpc", optional_argument, NULL, OPT_POWERPC }, { "ia64", optional_argument, NULL, OPT_IA64 }, { "arm", optional_argument, NULL, OPT_ARM }, + { "arm64", optional_argument, NULL, OPT_ARM64 }, { "armthumb", optional_argument, NULL, OPT_ARMTHUMB }, { "sparc", optional_argument, NULL, OPT_SPARC }, { "delta", optional_argument, NULL, OPT_DELTA }, @@ -355,6 +357,11 @@ parse_real(args_info *args, int argc, char **argv) options_bcj(optarg)); break; + case OPT_ARM64: + coder_add_filter(LZMA_FILTER_ARM64, + options_bcj(optarg)); + break; + case OPT_ARMTHUMB: coder_add_filter(LZMA_FILTER_ARMTHUMB, options_bcj(optarg)); diff --git a/src/xz/message.c b/src/xz/message.c index aa915d2..069bcf9 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -1004,13 +1004,15 @@ message_filters_to_str(char buf[FILTERS_STR_SIZE], case LZMA_FILTER_POWERPC: case LZMA_FILTER_IA64: case LZMA_FILTER_ARM: + case LZMA_FILTER_ARM64: case LZMA_FILTER_ARMTHUMB: case LZMA_FILTER_SPARC: { - static const char bcj_names[][9] = { + static const char bcj_names[][10] = { "x86", "powerpc", "ia64", "arm", + "arm64", "armthumb", "sparc", }; @@ -1211,6 +1213,7 @@ message_help(bool long_help) " --powerpc[=OPTS] PowerPC BCJ filter (big endian only)\n" " --ia64[=OPTS] IA-64 (Itanium) BCJ filter\n" " --arm[=OPTS] ARM BCJ filter (little endian only)\n" +" --arm64[=OPTS] ARM64 BCJ filter (little endian only)\n" " --armthumb[=OPTS] ARM-Thumb BCJ filter (little endian only)\n" " --sparc[=OPTS] SPARC BCJ filter\n" " Valid OPTS for all BCJ filters:\n" -- 2.12.3