Class: Omnizip::Filters::BcjArm64
- Inherits:
-
FilterBase
- Object
- FilterBase
- Omnizip::Filters::BcjArm64
- Defined in:
- lib/omnizip/filters/bcj_arm64.rb
Overview
BCJ filter for 64-bit ARM (AArch64) executables.
This filter preprocesses ARM64 machine code by converting relative addresses in B/BL (0x94) and ADRP (0x90) instructions to absolute addresses. ARM64 uses 4-byte aligned instructions with little-endian encoding.
The filter improves compression by making branch targets and page-aligned addresses position-independent.
Constant Summary collapse
- OPCODE_B_BL =
B/BL instruction base opcode
0x94000000- MASK_B_BL =
B/BL instruction mask
0xFC000000- OPCODE_ADRP =
ADRP instruction base opcode
0x90000000- MASK_ADRP =
ADRP instruction mask for variant detection
0x9F000000- INSTRUCTION_SIZE =
Size of ARM64 instruction (4 bytes)
4
Class Method Summary collapse
-
.metadata ⇒ Hash
Get metadata about this filter.
Instance Method Summary collapse
-
#decode(data, position = 0) ⇒ String
Decode (postprocess) ARM64 executable data after decompression.
-
#encode(data, position = 0) ⇒ String
Encode (preprocess) ARM64 executable data for compression.
Class Method Details
.metadata ⇒ Hash
Get metadata about this filter.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/omnizip/filters/bcj_arm64.rb', line 172 def { name: "BCJ-ARM64", description: "Branch converter for 64-bit ARM (AArch64) " \ "executables", architecture: "ARM64 / AArch64", alignment: 4, endian: "little", } end |
Instance Method Details
#decode(data, position = 0) ⇒ String
Decode (postprocess) ARM64 executable data after decompression.
Reverses the encoding by converting absolute addresses back to relative addresses.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/omnizip/filters/bcj_arm64.rb', line 117 def decode(data, position = 0) return data.dup if data.bytesize < INSTRUCTION_SIZE result = data.b size = data.bytesize & ~(INSTRUCTION_SIZE - 1) i = 0 pc = position - INSTRUCTION_SIZE while i < size instruction = extract_uint32_le(result, i) pc += INSTRUCTION_SIZE # Check for B/BL instruction if (instruction & MASK_B_BL) == OPCODE_B_BL # Extract absolute address and convert to relative offset absolute = (instruction & 0x03FFFFFF) << 2 offset = (absolute - pc) >> 2 new_instruction = OPCODE_B_BL | (offset & 0x03FFFFFF) write_uint32_le(result, i, new_instruction) i += INSTRUCTION_SIZE next end # Check for ADRP instruction if (instruction & MASK_ADRP) == OPCODE_ADRP # Extract immlo and immhi immlo = (instruction >> 29) & 0x3 immhi = (instruction >> 5) & 0x7FFFF # Combine into absolute page address absolute = ((immhi << 2) | immlo) << 12 # Convert to relative offset offset = (absolute - (pc & ~0xFFF)) >> 12 # Encode back as 21-bit value new_immlo = offset & 0x3 new_immhi = (offset >> 2) & 0x7FFFF new_instruction = (instruction & 0x9F00001F) | (new_immlo << 29) | (new_immhi << 5) write_uint32_le(result, i, new_instruction) end i += INSTRUCTION_SIZE end result end |
#encode(data, position = 0) ⇒ String
Encode (preprocess) ARM64 executable data for compression.
Scans for B/BL (0x94xxxxxx) and ADRP (0x90xxxxxx) instructions and converts relative addresses to absolute addresses.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/omnizip/filters/bcj_arm64.rb', line 54 def encode(data, position = 0) return data.dup if data.bytesize < INSTRUCTION_SIZE result = data.b size = data.bytesize & ~(INSTRUCTION_SIZE - 1) i = 0 pc = position - INSTRUCTION_SIZE while i < size instruction = extract_uint32_le(result, i) pc += INSTRUCTION_SIZE # Check for B/BL instruction (0x94xxxxxx) if (instruction & MASK_B_BL) == OPCODE_B_BL # Extract 26-bit offset, sign-extend, and convert offset = sign_extend_26(instruction & 0x03FFFFFF) absolute = (offset << 2) + pc new_instruction = OPCODE_B_BL | ((absolute >> 2) & 0x03FFFFFF) write_uint32_le(result, i, new_instruction) i += INSTRUCTION_SIZE next end # Check for ADRP instruction (0x90xxxxxx or 0xB0xxxxxx variants) if (instruction & MASK_ADRP) == OPCODE_ADRP # Extract immlo (bits [30:29]) and immhi (bits [23:5]) immlo = (instruction >> 29) & 0x3 immhi = (instruction >> 5) & 0x7FFFF # Combine into 21-bit offset offset = (immhi << 2) | immlo # Sign-extend 21-bit to full integer offset = sign_extend_21(offset) # Convert to absolute address (page-aligned, << 12) absolute = (offset << 12) + (pc & ~0xFFF) # Encode back absolute >>= 12 new_immlo = absolute & 0x3 new_immhi = (absolute >> 2) & 0x7FFFF new_instruction = (instruction & 0x9F00001F) | (new_immlo << 29) | (new_immhi << 5) write_uint32_le(result, i, new_instruction) end i += INSTRUCTION_SIZE end result end |