
org.tukaani.xz.simple.ARM64 Maven / Gradle / Ivy
The newest version!
// SPDX-License-Identifier: 0BSD
// SPDX-FileCopyrightText: The XZ for Java authors and contributors
// SPDX-FileContributor: Lasse Collin
// SPDX-FileContributor: Igor Pavlov
package org.tukaani.xz.simple;
import org.tukaani.xz.common.ByteArrayView;
// BCJ filter for ARM64 (AArch64) instructions
public final class ARM64 implements SimpleFilter {
private final boolean isEncoder;
private int pos;
public ARM64(boolean isEncoder, int startPos) {
this.isEncoder = isEncoder;
pos = startPos;
}
@Override
public int code(byte[] buf, int off, int len) {
int end = off + len - 4;
int i;
for (i = off; i <= end; i += 4) {
// Only the highest byte is needed to identify the BL and ADRP
// instructions.
int instr = buf[i + 3];
if ((instr & 0xFC) == 0x94) {
// BL instruction:
// The full 26-bit immediate is converted.
// The range is +/-128 MiB.
//
// Using the full range helps quite a lot with big
// executables. Smaller range would reduce false positives
// in non-code sections of the input though so this is
// a compromise that slightly favors big files. With the
// full range, only six bits of the 32 need to match to
// trigger a conversion.
instr = ByteArrayView.getIntLE(buf, i);
int pc = (pos + i - off) >>> 2;
if (!isEncoder)
pc = -pc;
instr = 0x94000000 | ((instr + pc) & 0x03FFFFFF);
ByteArrayView.setIntLE(buf, i, instr);
} else if ((instr & 0x9F) == 0x90) {
// ADRP instruction:
// Only values in the range +/-512 MiB are converted.
//
// Using less than the full +/-4 GiB range reduces false
// positives on non-code sections of the input while being
// excellent for executables up to 512 MiB. The positive
// effect of ADRP conversion is smaller than that of BL
// but it also doesn't hurt so much in non-code sections
// of input because, with +/-512 MiB range, nine bits of 32
// need to match to trigger a conversion (two 10-bit match
// choices = 9 bits).
instr = ByteArrayView.getIntLE(buf, i);
int src = ((instr >>> 29) & 3) | ((instr >>> 3) & 0x001FFFFC);
// With the addition only one branch is needed to
// check the +/- range. This is usually false when
// processing ARM64 code so branch prediction will
// handle it well in terms of performance.
//
// if ((src & 0x001E0000) != 0
// && (src & 0x001E0000) != 0x001E0000)
if (((src + 0x00020000) & 0x001C0000) != 0)
continue;
int pc = (pos + i - off) >>> 12;
if (!isEncoder)
pc = -pc;
int dest = src + pc;
instr &= 0x9000001F;
instr |= (dest & 3) << 29;
instr |= (dest & 0x0003FFFC) << 3;
instr |= (-(dest & 0x00020000)) & 0x00E00000;
ByteArrayView.setIntLE(buf, i, instr);
}
}
i -= off;
pos += i;
return i;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy