Class: Omnizip::Filters::BcjArm
- Inherits:
-
FilterBase
- Object
- FilterBase
- Omnizip::Filters::BcjArm
- Defined in:
- lib/omnizip/filters/bcj_arm.rb
Overview
BCJ filter for 32-bit ARM executables.
This filter preprocesses ARM machine code by converting relative addresses in BL (Branch and Link - 0xEB) instructions to absolute addresses. ARM uses 4-byte aligned instructions with little-endian encoding.
The filter improves compression by making branch targets position-independent. The offset in ARM BL instructions is stored as word offset (divided by 4), and is relative to PC+8.
Constant Summary collapse
- OPCODE_BL =
ARM BL (Branch and Link) opcode
0xEB- INSTRUCTION_SIZE =
Size of ARM instruction (4 bytes, little-endian)
4- OFFSET_MASK =
Offset mask (24-bit offset in BL instruction)
0x00FFFFFF
Class Method Summary collapse
-
.metadata ⇒ Hash
Get metadata about this filter.
Instance Method Summary collapse
-
#decode(data, position = 0) ⇒ String
Decode (postprocess) ARM executable data after decompression.
-
#encode(data, position = 0) ⇒ String
Encode (preprocess) ARM executable data for compression.
Class Method Details
.metadata ⇒ Hash
Get metadata about this filter.
133 134 135 136 137 138 139 140 141 |
# File 'lib/omnizip/filters/bcj_arm.rb', line 133 def { name: "BCJ-ARM", description: "Branch converter for 32-bit ARM executables", architecture: "ARM (32-bit)", alignment: 4, endian: "little", } end |
Instance Method Details
#decode(data, position = 0) ⇒ String
Decode (postprocess) ARM executable data after decompression.
Reverses the encoding by converting absolute word offsets back to relative word offsets.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/omnizip/filters/bcj_arm.rb', line 93 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 starts at position + 4 (as per C implementation) pc = position + 4 while i < size # Advance PC to current instruction position current_pc = pc + i # Check if last byte is 0xEB (BL instruction) if result.getbyte(i + 3) == OPCODE_BL # Extract full 32-bit instruction value instruction = extract_uint32_le(result, i) # Calculate word offset from PC word_offset = current_pc >> 2 # Subtract word offset from instruction value instruction -= word_offset # Mask to 24-bit and combine with opcode instruction = (instruction & OFFSET_MASK) | 0xEB000000 write_uint32_le(result, i, instruction) end i += INSTRUCTION_SIZE end result end |
#encode(data, position = 0) ⇒ String
Encode (preprocess) ARM executable data for compression.
Scans for BL (0xEB) opcodes and converts relative word offsets to absolute word offsets. ARM branch offset is relative to PC+8.
49 50 51 52 53 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 |
# File 'lib/omnizip/filters/bcj_arm.rb', line 49 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 starts at position + 4 (as per C implementation) pc = position + 4 while i < size # Advance PC to current instruction position current_pc = pc + i # Check if last byte is 0xEB (BL instruction) if result.getbyte(i + 3) == OPCODE_BL # Extract full 32-bit instruction value instruction = extract_uint32_le(result, i) # Calculate word offset from PC word_offset = current_pc >> 2 # Add word offset to instruction value instruction += word_offset # Mask to 24-bit and combine with opcode instruction = (instruction & OFFSET_MASK) | 0xEB000000 write_uint32_le(result, i, instruction) end i += INSTRUCTION_SIZE end result end |