From bb5cdbd1230394ad1611ae03b3c5ac9d0d157994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E6=80=A1=E7=84=B6?= Date: Sat, 18 Apr 2026 11:01:27 +0800 Subject: [PATCH] add ARM64 decoder --- un7zip/src/main/cpp/src/7zDec.c | 3 ++ un7zip/src/main/cpp/src/Bra.c | 59 +++++++++++++++++++++++++++++++++ un7zip/src/main/cpp/src/Bra.h | 1 + 3 files changed, 63 insertions(+) diff --git a/un7zip/src/main/cpp/src/7zDec.c b/un7zip/src/main/cpp/src/7zDec.c index 7c46352..9bbb9c5 100644 --- a/un7zip/src/main/cpp/src/7zDec.c +++ b/un7zip/src/main/cpp/src/7zDec.c @@ -31,6 +31,7 @@ #define k_ARM 0x3030501 #define k_ARMT 0x3030701 #define k_SPARC 0x3030805 +#define k_ARM64 0xA #ifdef _7ZIP_PPMD_SUPPPORT @@ -333,6 +334,7 @@ static SRes CheckSupportedFolder(const CSzFolder *f) case k_SPARC: case k_ARM: case k_ARMT: + case k_ARM64: break; default: return SZ_ERROR_UNSUPPORTED; @@ -532,6 +534,7 @@ static SRes SzFolder_Decode2(const CSzFolder *folder, CASE_BRA_CONV(SPARC) CASE_BRA_CONV(ARM) CASE_BRA_CONV(ARMT) + CASE_BRA_CONV(ARM64) default: return SZ_ERROR_UNSUPPORTED; } diff --git a/un7zip/src/main/cpp/src/Bra.c b/un7zip/src/main/cpp/src/Bra.c index aed17e3..c3e11cd 100644 --- a/un7zip/src/main/cpp/src/Bra.c +++ b/un7zip/src/main/cpp/src/Bra.c @@ -61,6 +61,65 @@ SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) } +SizeT ARM64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) +{ + /* + * ARM64 Branch/Call/Jump (BCJ) filter decoder + * Adapted from xz-embedded project by Lasse Collin and Igor Pavlov + * This file has been put into the public domain. + */ + + SizeT i; + UInt32 instr; + UInt32 addr; + + size &= ~(SizeT)3; /* Align to 4 bytes */ + + for (i = 0; i + 4 <= size; i += 4) + { + instr = GetUi32(data + i); + + if ((instr >> 26) == 0x25) + { + /* BL (Branch with Link) instruction */ + addr = instr & 0x03FFFFFF; + + if (encoding) + addr += (ip + (UInt32)i) >> 2; + else + addr -= (ip + (UInt32)i) >> 2; + + instr = 0x94000000 | (addr & 0x03FFFFFF); + + SetUi32(data + i, instr); + } + else if ((instr & 0x9F000000) == 0x90000000) + { + /* ADRP (Address of a Page) instruction */ + addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC); + + /* Only convert values in the range +/-512 MiB */ + if ((addr + 0x020000) & 0x1C0000) + continue; + + if (encoding) + addr += (ip + (UInt32)i) >> 12; + else + addr -= (ip + (UInt32)i) >> 12; + + instr &= 0x9000001F; + instr |= (addr & 3) << 29; + instr |= (addr & 0x03FFFC) << 3; + instr |= (0U - (addr & 0x020000)) & 0xE00000; + + SetUi32(data + i, instr); + } + } + + return i; +} + + SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding) { Byte *p; diff --git a/un7zip/src/main/cpp/src/Bra.h b/un7zip/src/main/cpp/src/Bra.h index 855e37a..77bb84c 100644 --- a/un7zip/src/main/cpp/src/Bra.h +++ b/un7zip/src/main/cpp/src/Bra.h @@ -58,6 +58,7 @@ SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); +SizeT ARM64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding); EXTERN_C_END