mirror of
https://github.com/radareorg/radare2.git
synced 2024-10-08 19:33:31 +00:00
New arm64 instruction support (#8140)
* Add cmp for reg, reg * Add strb instruction to arm64 * Add b.eq instruction arm64 * Add byte store ops * Add str and ldr ops
This commit is contained in:
parent
f20edcc5ee
commit
6c666bf142
@ -23,6 +23,13 @@ typedef enum regtype_t {
|
||||
ARM_SIMD = 16
|
||||
} RegType;
|
||||
|
||||
typedef enum shifttype_t {
|
||||
ARM_NO_SHIFT = -1,
|
||||
ARM_LSL = 0,
|
||||
ARM_LSR = 1,
|
||||
ARM_ASR = 2
|
||||
} ShiftType;
|
||||
|
||||
typedef struct operand_t {
|
||||
OpType type;
|
||||
union {
|
||||
@ -36,8 +43,8 @@ typedef struct operand_t {
|
||||
int sign;
|
||||
};
|
||||
struct {
|
||||
ut64 lsl;
|
||||
ut64 shift;
|
||||
ut64 shift_amount;
|
||||
ShiftType shift;
|
||||
};
|
||||
struct {
|
||||
ut32 mem_option;
|
||||
@ -60,7 +67,7 @@ static int get_mem_option(char *token) {
|
||||
// values 4, 8, 12, are unused. XXX to adjust
|
||||
const char *options[] = {"sy", "st", "ld", "xxx", "ish", "ishst",
|
||||
"ishld", "xxx", "nsh", "nshst", "nshld",
|
||||
"xxx", "osh", "oshst", "oshld", NULL};
|
||||
"xxx", "osh", "oshst", "oshld", NULL};
|
||||
int i = 0;
|
||||
while (options[i]) {
|
||||
if (!strcasecmp (token, options[i])) {
|
||||
@ -71,6 +78,121 @@ static int get_mem_option(char *token) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int countLeadingZeros(ut32 x) {
|
||||
int count = 0;
|
||||
while (x) {
|
||||
x >>= 1;
|
||||
--count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int countTrailingZeros(ut32 x) {
|
||||
int count = 0;
|
||||
while (x > 0) {
|
||||
if ((x & 1) == 1) {
|
||||
break;
|
||||
} else {
|
||||
count ++;
|
||||
x = x >> 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int calcNegOffset(int n, int shift) {
|
||||
int a = n >> shift;
|
||||
if (a == 0) {
|
||||
return 0xff;
|
||||
}
|
||||
// find first set bit then invert it and all
|
||||
// bits below it
|
||||
int t = 0x400;
|
||||
while (!(t & a) && a != 0 && t != 0) {
|
||||
t = t >> 1;
|
||||
}
|
||||
t = t & (t - 1);
|
||||
a = a ^ t;
|
||||
// If bits below 32 are set
|
||||
if (countTrailingZeros(n) > shift) {
|
||||
a--;
|
||||
}
|
||||
return 0xff & (0xff - a);
|
||||
}
|
||||
|
||||
static int rol(ut32 n, int i) {
|
||||
return ((n << i) | (n >> (32 - i))) >> 0;
|
||||
}
|
||||
|
||||
static int ror(ut32 n, int i) {
|
||||
return ((n >> i) | (n << (32 - i))) >> 0;
|
||||
}
|
||||
|
||||
static int encode(int n) {
|
||||
int i, m;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
m = rol(n, i * 2);
|
||||
if (m < 256) {
|
||||
return (i << 8) | m;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int countLeadingOnes(ut32 x) {
|
||||
return countLeadingZeros (~x);
|
||||
}
|
||||
|
||||
static int countTrailingOnes(ut32 x) {
|
||||
return countTrailingZeros (~x);
|
||||
}
|
||||
|
||||
static bool isMask(ut32 value) {
|
||||
return value && ((value + 1) & value) == 0;
|
||||
}
|
||||
|
||||
static bool isShiftedMask (ut32 value) {
|
||||
return value && isMask ((value - 1) | value);
|
||||
}
|
||||
|
||||
static ut32 decodeBitMasks(ut32 imm) {
|
||||
// get element size
|
||||
int size = 32;
|
||||
// determine rot to make element be 0^m 1^n
|
||||
ut32 cto, i;
|
||||
ut32 mask = ((ut64) - 1LL) >> (64 - size);
|
||||
|
||||
if (isShiftedMask (imm)) {
|
||||
i = countTrailingZeros (imm);
|
||||
cto = countTrailingOnes (imm >> i);
|
||||
} else {
|
||||
imm |= ~mask;
|
||||
if (!isShiftedMask (imm)) {
|
||||
return UT32_MAX;
|
||||
}
|
||||
|
||||
ut32 clo = countLeadingOnes (imm);
|
||||
i = 64 - clo;
|
||||
cto = clo + countTrailingOnes (imm) - (64 - size);
|
||||
}
|
||||
|
||||
// Encode in Immr the number of RORs it would take to get *from* 0^m 1^n
|
||||
// to our target value, where I is the number of RORs to go the opposite
|
||||
// direction
|
||||
ut32 immr = (size - i) & (size - 1);
|
||||
// If size has a 1 in the n'th bit, create a value that has zeroes in
|
||||
// bits [0, n] and ones above that.
|
||||
ut64 nimms = ~(size - 1) << 1;
|
||||
// Or the cto value into the low bits, which must be below the Nth bit
|
||||
// bit mentioned above.
|
||||
nimms |= (cto - 1);
|
||||
// Extract and toggle seventh bit to make N field.
|
||||
ut32 n = ((nimms >> 6) & 1) ^ 1;
|
||||
ut64 encoding = (n << 12) | (immr << 6) | (nimms & 0x3f);
|
||||
return encoding;
|
||||
}
|
||||
|
||||
static ut32 mov(ArmOp *op) {
|
||||
int k = 0;
|
||||
ut32 data = UT32_MAX;
|
||||
@ -112,13 +234,202 @@ static ut32 mov(ArmOp *op) {
|
||||
}
|
||||
|
||||
data = k;
|
||||
//printf ("Immediate %d\n", op->operands[1].immediate);
|
||||
data |= (op->operands[0].reg << 24); // arg(0)
|
||||
data |= ((op->operands[1].immediate & 7) << 29); // arg(1)
|
||||
data |= (((op->operands[1].immediate >> 3) & 0xff) << 16); // arg(1)
|
||||
data |= ((op->operands[1].immediate >> 10) << 7); // arg(1)
|
||||
return data;
|
||||
}
|
||||
|
||||
static ut32 cmp(ArmOp *op) {
|
||||
ut32 data = UT32_MAX;
|
||||
int k = 0;
|
||||
if (op->operands[0].reg_type & ARM_REG64 && op->operands[1].reg_type & ARM_REG64) {
|
||||
k = 0x1f0000eb;
|
||||
} else if (op->operands[0].reg_type & ARM_REG32 && op->operands[1].reg_type & ARM_REG32) {
|
||||
if (op->operands[2].shift_amount > 31) {
|
||||
return UT32_MAX;
|
||||
}
|
||||
k = 0x1f00006b;
|
||||
} else {
|
||||
return UT32_MAX;
|
||||
}
|
||||
|
||||
data = k | (op->operands[0].reg & 0x18) << 13 | op->operands[0].reg << 29 | op->operands[1].reg << 8;
|
||||
|
||||
if (op->operands[2].shift != ARM_NO_SHIFT) {
|
||||
data |= op->operands[2].shift_amount << 18 | op->operands[2].shift << 14;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static ut32 sturop(ArmOp *op, int k) {
|
||||
ut32 data = UT32_MAX;
|
||||
|
||||
if (op->operands[1].reg_type & ARM_REG32) {
|
||||
return data;
|
||||
}
|
||||
if (op->operands[0].reg_type & ARM_REG32) {
|
||||
k -= 0x40;
|
||||
}
|
||||
if (op->operands[2].type & ARM_GPR) {
|
||||
return data;
|
||||
}
|
||||
|
||||
int n = op->operands[2].immediate;
|
||||
if (n > 0xff || n < -0x100) {
|
||||
return data;
|
||||
}
|
||||
|
||||
data = k | op->operands[0].reg << 24 | op->operands[1].reg << 29 | (op->operands[1].reg & 56) << 13;
|
||||
|
||||
if (n < 0) {
|
||||
n *= -1;
|
||||
data |= ( 0xf & (0xf - (n - 1)) ) << 20;
|
||||
|
||||
if (countTrailingZeros(n) > 3) {
|
||||
data |= (0x1f - ((n >> 4) - 1)) << 8;
|
||||
} else {
|
||||
data |= (0x1f - (n >> 4)) << 8;
|
||||
}
|
||||
} else {
|
||||
data |= (0xf & (n & 63)) << 20;
|
||||
if (countTrailingZeros(n) < 4) {
|
||||
data |= (n >> 4) << 8;
|
||||
} else {
|
||||
data |= (0xff & n) << 4;
|
||||
}
|
||||
data |= (n >> 8) << 8;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Register Load/store ops
|
||||
static ut32 reglsop(ArmOp *op, int k) {
|
||||
ut32 data = UT32_MAX;
|
||||
|
||||
if (op->operands[1].reg_type & ARM_REG32) {
|
||||
return data;
|
||||
}
|
||||
if (op->operands[0].reg_type & ARM_REG32) {
|
||||
k -= 0x40;
|
||||
}
|
||||
if (op->operands[2].type & ARM_GPR) {
|
||||
k += 0x00682000;
|
||||
data = k | op->operands[0].reg << 24 | op->operands[1].reg << 29 | (op->operands[1].reg & 56) << 13;
|
||||
data |= op->operands[2].reg << 8;
|
||||
} else {
|
||||
int n = op->operands[2].immediate;
|
||||
if (n > 0x100 || n < -0x100) {
|
||||
return UT32_MAX;
|
||||
}
|
||||
|
||||
if (n == 0 || (n > 0 && countTrailingZeros(n) >= 4)) {
|
||||
k ++;
|
||||
}
|
||||
data = k | op->operands[0].reg << 24 | op->operands[1].reg << 29 | (op->operands[1].reg & 56) << 13;
|
||||
|
||||
if (n < 0) {
|
||||
n *= -1;
|
||||
data |= ( 0xf & (0xf - (n - 1)) ) << 20;
|
||||
if (countTrailingZeros(n) > 3) {
|
||||
data |= (0x1f - ((n >> 4) - 1)) << 8;
|
||||
} else {
|
||||
data |= (0x1f - (n >> 4)) << 8;
|
||||
}
|
||||
} else {
|
||||
if (op->operands[0].reg_type & ARM_REG32) {
|
||||
if (countTrailingZeros(n) < 2) {
|
||||
data |= (0xf & (n & 63)) << 20;
|
||||
data |= (n >> 4) << 8;
|
||||
} else {
|
||||
data++;
|
||||
data |= (0xff & n) << 16;
|
||||
}
|
||||
data |= (n >> 8) << 8;
|
||||
} else {
|
||||
data |= (0xf & (n & 63)) << 20;
|
||||
if (countTrailingZeros(n) < 4) {
|
||||
data |= (n >> 4) << 8;
|
||||
} else {
|
||||
data |= (0xff & n) << 15;
|
||||
}
|
||||
data |= (n >> 8) << 23;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// Byte load/store ops
|
||||
static ut32 bytelsop(ArmOp *op, int k) {
|
||||
ut32 data = UT32_MAX;
|
||||
|
||||
if (op->operands[0].reg_type & ARM_REG64) {
|
||||
return data;
|
||||
}
|
||||
if (op->operands[1].reg_type & ARM_REG32) {
|
||||
return data;
|
||||
}
|
||||
if (op->operands[2].type & ARM_GPR) {
|
||||
if ((k & 0xf) != 8) {
|
||||
k--;
|
||||
}
|
||||
k += 0x00682000;
|
||||
data = k | op->operands[0].reg << 24 | op->operands[1].reg << 29 | (op->operands[1].reg & 56) << 13;
|
||||
data |= op->operands[2].reg << 8;
|
||||
return data;
|
||||
}
|
||||
|
||||
int n = op->operands[2].immediate;
|
||||
if (n > 0xfff || n < -0x100) {
|
||||
return UT32_MAX;
|
||||
}
|
||||
// Half ops
|
||||
int halfop = false;
|
||||
if ((k & 0xf) == 8) {
|
||||
halfop = true;
|
||||
if (n == 0 || (countTrailingZeros(n) && n > 0)) {
|
||||
k++;
|
||||
}
|
||||
} else {
|
||||
if (n < 0) {
|
||||
k--;
|
||||
}
|
||||
}
|
||||
|
||||
data = k | op->operands[0].reg << 24 | op->operands[1].reg << 29 | (op->operands[1].reg & 56) << 13;
|
||||
|
||||
int imm = n;
|
||||
int low_shift = 20;
|
||||
int high_shift = 8;
|
||||
int top_shift = 10;
|
||||
if (n < 0) {
|
||||
imm = 0xfff + (n + 1);
|
||||
}
|
||||
if (halfop) {
|
||||
if (imm & 0x1 || n < 0) {
|
||||
data |= (0xf & imm) << low_shift ;
|
||||
data |= (0x7 & (imm >> 4)) << high_shift;
|
||||
data |= (0x7 & (imm >> 6)) << top_shift;
|
||||
} else {
|
||||
data |= (0xf & imm) << (low_shift - 3);
|
||||
data |= (0x7 & (imm >> 4)) << (high_shift + 13);
|
||||
data |= (0x7 & (imm >> 7)) << (top_shift - 2);
|
||||
}
|
||||
} else {
|
||||
if (n < 0) {
|
||||
data |= (0xf & imm) << 20;
|
||||
data |= (0x1f & (imm >> 4)) << 8;
|
||||
} else {
|
||||
data |= (0xf & imm) << 18;
|
||||
data |= (0x3 & (imm >> 4)) << 22;
|
||||
data |= (0x7 & (imm >> 6)) << 8;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static ut32 branch(ArmOp *op, ut64 addr, int k) {
|
||||
@ -154,6 +465,37 @@ static ut32 branch(ArmOp *op, ut64 addr, int k) {
|
||||
return data;
|
||||
}
|
||||
|
||||
static ut32 bdot(ArmOp *op, ut64 addr, int k) {
|
||||
ut32 data = UT32_MAX;
|
||||
int n = 0;
|
||||
int a = 0;
|
||||
int tz = 0;
|
||||
n = op->operands[0].immediate;
|
||||
// I am sure there's a logical way to do negative offsets,
|
||||
// but I was unable to find any sensible docs so I did my best
|
||||
if (!(n & 0x3 || n > 0x7ffffff)) {
|
||||
n -= addr;
|
||||
data = k;
|
||||
if (n < 0) {
|
||||
n *= -1;
|
||||
a = (n << 3) - 1;
|
||||
data |= (0xff - a) << 24;
|
||||
|
||||
a = calcNegOffset(n, 5);
|
||||
data |= a << 16;
|
||||
|
||||
a = calcNegOffset(n, 13);
|
||||
data |= a << 8;
|
||||
} else {
|
||||
data |= (n & 31) << 27;
|
||||
data |= (0xff & (n >> 5)) << 16;
|
||||
data |= (0xff & (n >> 13)) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static ut32 mem_barrier (ArmOp *op, ut64 addr, int k) {
|
||||
ut32 data = UT32_MAX;
|
||||
data = k;
|
||||
@ -231,81 +573,6 @@ static ut32 msr(ArmOp *op, int w) {
|
||||
return data;
|
||||
}
|
||||
|
||||
static int countLeadingZeros(ut32 x) {
|
||||
int count = 0;
|
||||
while (x) {
|
||||
x >>= 1;
|
||||
--count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int countTrailingZeros(ut32 x) {
|
||||
int count = 0;
|
||||
while (x > 0) {
|
||||
if ((x & 1) == 1) {
|
||||
break;
|
||||
} else {
|
||||
count ++;
|
||||
x = x >> 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int countLeadingOnes(ut32 x) {
|
||||
return countLeadingZeros (~x);
|
||||
}
|
||||
|
||||
static int countTrailingOnes(ut32 x) {
|
||||
return countTrailingZeros (~x);
|
||||
}
|
||||
|
||||
static bool isMask(ut32 value) {
|
||||
return value && ((value + 1) & value) == 0;
|
||||
}
|
||||
|
||||
static bool isShiftedMask (ut32 value) {
|
||||
return value && isMask ((value - 1) | value);
|
||||
}
|
||||
|
||||
static ut32 decodeBitMasks(ut32 imm) {
|
||||
// get element size
|
||||
int size = 32;
|
||||
// determine rot to make element be 0^m 1^n
|
||||
ut32 cto, i;
|
||||
ut32 mask = ((ut64) - 1LL) >> (64 - size);
|
||||
|
||||
if (isShiftedMask (imm)) {
|
||||
i = countTrailingZeros (imm);
|
||||
cto = countTrailingOnes (imm >> i);
|
||||
} else {
|
||||
imm |= ~mask;
|
||||
if (!isShiftedMask (imm)) {
|
||||
return UT32_MAX;
|
||||
}
|
||||
|
||||
ut32 clo = countLeadingOnes (imm);
|
||||
i = 64 - clo;
|
||||
cto = clo + countTrailingOnes (imm) - (64 - size);
|
||||
}
|
||||
|
||||
// Encode in Immr the number of RORs it would take to get *from* 0^m 1^n
|
||||
// to our target value, where I is the number of RORs to go the opposite
|
||||
// direction
|
||||
ut32 immr = (size - i) & (size - 1);
|
||||
// If size has a 1 in the n'th bit, create a value that has zeroes in
|
||||
// bits [0, n] and ones above that.
|
||||
ut64 nimms = ~(size - 1) << 1;
|
||||
// Or the cto value into the low bits, which must be below the Nth bit
|
||||
// bit mentioned above.
|
||||
nimms |= (cto - 1);
|
||||
// Extract and toggle seventh bit to make N field.
|
||||
ut32 n = ((nimms >> 6) & 1) ^ 1;
|
||||
ut64 encoding = (n << 12) | (immr << 6) | (nimms & 0x3f);
|
||||
return encoding;
|
||||
}
|
||||
|
||||
static ut32 orr(ArmOp *op, int addr) {
|
||||
ut32 data = UT32_MAX;
|
||||
|
||||
@ -390,7 +657,6 @@ static ut32 adrp(ArmOp *op, ut64 addr, ut32 k) { //, int reg, ut64 dst) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static ut32 adr(ArmOp *op, int addr) {
|
||||
ut32 data = UT32_MAX;
|
||||
ut64 at = 0LL;
|
||||
@ -471,6 +737,30 @@ static bool parseOperands(char* str, ArmOp *op) {
|
||||
}
|
||||
op->operands[operand].type = ARM_NOTYPE;
|
||||
op->operands[operand].reg_type = ARM_UNDEFINED;
|
||||
op->operands[operand].shift = ARM_NO_SHIFT;
|
||||
|
||||
while (token[0] == ' ' || token[0] == '[' || token[0] == ']') {
|
||||
token ++;
|
||||
}
|
||||
|
||||
if (!strncmp (token, "lsl", 3)) {
|
||||
op->operands[operand].shift = ARM_LSL;
|
||||
} else if (!strncmp (token, "lsr", 3)) {
|
||||
op->operands[operand].shift = ARM_LSR;
|
||||
} else if (!strncmp (token, "asr", 3)) {
|
||||
op->operands[operand].shift = ARM_ASR;
|
||||
}
|
||||
if (op->operands[operand].shift != ARM_NO_SHIFT) {
|
||||
op->operands_count ++;
|
||||
op->operands[operand].shift_amount = r_num_math (NULL, token + 4);
|
||||
if (op->operands[operand].shift_amount > 63) {
|
||||
return false;
|
||||
}
|
||||
operand ++;
|
||||
token = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (token[0]) {
|
||||
case 'x':
|
||||
x = strchr (token, ',');
|
||||
@ -481,12 +771,18 @@ static bool parseOperands(char* str, ArmOp *op) {
|
||||
op->operands[operand].type = ARM_GPR;
|
||||
op->operands[operand].reg_type = ARM_REG64;
|
||||
op->operands[operand].reg = r_num_math (NULL, token + 1);
|
||||
if (op->operands[operand].reg > 31) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
op->operands_count ++;
|
||||
op->operands[operand].type = ARM_GPR;
|
||||
op->operands[operand].reg_type = ARM_REG32;
|
||||
op->operands[operand].reg = r_num_math (NULL, token + 1);
|
||||
if (op->operands[operand].reg > 31) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
op->operands_count ++;
|
||||
@ -506,7 +802,7 @@ static bool parseOperands(char* str, ArmOp *op) {
|
||||
op->operands_count ++;
|
||||
op->operands[operand].type = ARM_GPR;
|
||||
op->operands[operand].reg_type = ARM_SP | ARM_REG64;
|
||||
op->operands[operand].reg = r_num_math (NULL, token + 1);
|
||||
op->operands[operand].reg = 31;
|
||||
break;
|
||||
}
|
||||
mem_opt = get_mem_option (token);
|
||||
@ -544,6 +840,7 @@ static bool parseOperands(char* str, ArmOp *op) {
|
||||
break;
|
||||
}
|
||||
token = next;
|
||||
|
||||
operand ++;
|
||||
if (operand > MAX_OPERANDS) {
|
||||
free (t);
|
||||
@ -571,13 +868,57 @@ static bool parseOpcode(const char *str, ArmOp *op) {
|
||||
bool arm64ass(const char *str, ut64 addr, ut32 *op) {
|
||||
ArmOp ops = {0};
|
||||
if (!parseOpcode (str, &ops)) {
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
/* TODO: write tests for this and move out the regsize logic into the mov */
|
||||
if (!strncmp (str, "mov", 3)) {
|
||||
*op = mov (&ops);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "cmp", 3)) {
|
||||
*op = cmp (&ops);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldrb", 4)) {
|
||||
*op = bytelsop (&ops, 0x00004039);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldrh", 4)) {
|
||||
*op = bytelsop (&ops, 0x00004078);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldrsh", 5)) {
|
||||
*op = bytelsop (&ops, 0x0000c078);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldrsw", 5)) {
|
||||
*op = bytelsop (&ops, 0x000080b8);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldrsb", 5)) {
|
||||
*op = bytelsop (&ops, 0x0000c039);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "strb", 4)) {
|
||||
*op = bytelsop (&ops, 0x00000039);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "strh", 4)) {
|
||||
*op = bytelsop (&ops, 0x00000078);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "ldr", 3)) {
|
||||
*op = reglsop (&ops, 0x000040f8);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "stur", 4)) {
|
||||
*op = sturop (&ops, 0x000000f8);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "str", 3)) {
|
||||
*op = reglsop (&ops, 0x000000f8);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "sub", 3)) { // w
|
||||
*op = arithmetic (&ops, 0xd1);
|
||||
return *op != -1;
|
||||
@ -591,7 +932,7 @@ bool arm64ass(const char *str, ut64 addr, ut32 *op) {
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "adrp x", 6)) {
|
||||
*op = adrp (&ops, addr, 0x000000d0);
|
||||
*op = adrp (&ops, addr, 0x00000090);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strcmp (str, "nop")) {
|
||||
@ -642,6 +983,14 @@ bool arm64ass(const char *str, ut64 addr, ut32 *op) {
|
||||
*op = branch (&ops, addr, 0x14);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "b.eq ", 5)) {
|
||||
*op = bdot (&ops, addr, 0x00000054);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "b.hs ", 5)) {
|
||||
*op = bdot (&ops, addr, 0x02000054);
|
||||
return *op != -1;
|
||||
}
|
||||
if (!strncmp (str, "bl ", 3)) {
|
||||
*op = branch (&ops, addr, 0x94);
|
||||
return *op != -1;
|
||||
|
Loading…
Reference in New Issue
Block a user