Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153562767
D5217.id13087.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D5217.id13087.diff
View Options
Index: sys/arm64/arm64/disassem.c
===================================================================
--- sys/arm64/arm64/disassem.c
+++ sys/arm64/arm64/disassem.c
@@ -38,6 +38,16 @@
#define ARM64_MAX_TOKEN_LEN 8
#define ARM64_MAX_TOKEN_CNT 10
+#define ARM_INSN_SIZE_OFFSET 30
+#define ARM_INSN_SIZE_MASK 0x3
+
+/* Special options for instruction printing */
+#define OP_SIGN_EXT (1UL << 0) /* Sign-extend immediate value */
+#define OP_LITERAL (1UL << 1) /* Use literal (memory offset) */
+#define OP_MULT_4 (1UL << 2) /* Multiply immediate by 4 */
+#define OP_SF32 (1UL << 3) /* Force 32-bit access */
+#define OP_SF_INV (1UL << 6) /* SF is inverted (1 means 32 bit access) */
+
static const char *w_reg[] = {
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
@@ -74,6 +84,10 @@
enum arm64_format_type {
TYPE_01, /* OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64
OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 */
+ TYPE_02, /* OP <RT>, [<RN>, #<imm>]{!}] SF32/64
+ OP <RT>, [<RN>], #<imm>{!} SF32/64
+ OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } */
+ TYPE_03, /* OP <RT>, #imm SF32/64 */
};
/*
@@ -112,11 +126,56 @@
* SHIFT - type of shift (instruction dependent)
* IMM - immediate value
* Rx - register number
+ * OPTION - command specific options
+ * SCALE - scaling of immediate value
*/
static struct arm64_insn arm64_i[] = {
- { "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)", TYPE_01, 0 },
- { "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)", TYPE_01, 0 },
- { "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)", TYPE_01, 0 },
+ { "add", "SF(1)|0001011|SHIFT(2)|0|RM(5)|IMM(6)|RN(5)|RD(5)",
+ TYPE_01, 0 },
+ { "mov", "SF(1)|001000100000000000000|RN(5)|RD(5)",
+ TYPE_01, 0 },
+ { "add", "SF(1)|0010001|SHIFT(2)|IMM(12)|RN(5)|RD(5)",
+ TYPE_01, 0 },
+ { "ldr", "1|SF(1)|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
+ TYPE_02, OP_SIGN_EXT }, /* ldr immediate post/pre index */
+ { "ldr", "1|SF(1)|11100101|IMM(12)|RN(5)|RT(5)",
+ TYPE_02, 0 }, /* ldr immediate unsigned */
+ { "ldr", "1|SF(1)|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, 0 }, /* ldr register */
+ { "ldr", "0|SF(1)|011000|IMM(19)|RT(5)",
+ TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */
+ { "ldrb", "00|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)",
+ TYPE_02, OP_SIGN_EXT | OP_SF32 }, /* ldrb immediate post/pre index */
+ { "ldrb", "00|11100101|IMM(12)|RN(5)|RT(5)",
+ TYPE_02, OP_SF32 }, /* ldrb immediate unsigned */
+ { "ldrb", "00|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, OP_SF32 }, /* ldrb register */
+ { "ldrh", "01|111000010|IMM(9)|OPTION(2)|RN(5)|RT(5)", TYPE_02,
+ OP_SIGN_EXT | OP_SF32 }, /* ldrh immediate post/pre index */
+ { "ldrh", "01|11100101|IMM(12)|RN(5)|RT(5)",
+ TYPE_02, OP_SF32 }, /* ldrh immediate unsigned */
+ { "ldrh", "01|111000011|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, OP_SF32 }, /* ldrh register */
+ { "ldrsb", "001110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
+ TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsb immediate post/pre index */
+ { "ldrsb", "001110011|SF(1)|IMM(12)|RN(5)|RT(5)",\
+ TYPE_02, OP_SF_INV}, /* ldrsb immediate unsigned */
+ { "ldrsb", "001110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, OP_SF_INV }, /* ldrsb register */
+ { "ldrsh", "011110001|SF(1)|0|IMM(9)|OPTION(2)|RN(5)|RT(5)",
+ TYPE_02, OP_SIGN_EXT | OP_SF_INV }, /* ldrsh immediate post/pre index */
+ { "ldrsh", "011110011|SF(1)|IMM(12)|RN(5)|RT(5)",
+ TYPE_02, OP_SF_INV}, /* ldrsh immediate unsigned */
+ { "ldrsh", "011110001|SF(1)|1|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, OP_SF_INV }, /* ldrsh register */
+ { "ldrsw", "10111000100|IMM(9)|OPTION(2)|RN(5)|RT(5)",
+ TYPE_02, OP_SIGN_EXT }, /* ldrsw immediate post/pre index */
+ { "ldrsw", "1011100110|IMM(12)|RN(5)|RT(5)",
+ TYPE_02, 0 }, /* ldrsw immediate unsigned */
+ { "ldrsw", "10111000101|RM(5)|OPTION(3)|SCALE(1)|10|RN(5)|RT(5)",
+ TYPE_02, 0 }, /* ldrsw register */
+ { "ldrsw", "10011000|IMM(19)|RT(5)",
+ TYPE_03, OP_SIGN_EXT | OP_LITERAL | OP_MULT_4 }, /* ldr literal */
{ NULL, NULL }
};
@@ -240,6 +299,29 @@
return (EINVAL);
}
+static int
+arm64_disasm_read_token_sign_ext(struct arm64_insn *insn, u_int opcode,
+ const char *token, int *val)
+{
+ int i;
+ int msk;
+
+ for (i = 0; i < ARM64_MAX_TOKEN_CNT; i++) {
+ if (strcmp(insn->tokens[i].name, token) == 0) {
+ msk = (1 << insn->tokens[i].len) - 1;
+ *val = ((opcode >> insn->tokens[i].pos) & msk);
+
+ /* If last bit is 1, sign-extend the value */
+ if (*val & (1 << (insn->tokens[i].len - 1)))
+ *val |= ~msk;
+
+ return (0);
+ }
+ }
+
+ return (EINVAL);
+}
+
static const char *
arm64_reg(int b64, int num)
{
@@ -257,11 +339,13 @@
uint32_t insn;
int matchp;
int ret;
- int shift, rm, rd, rn, imm, sf;
+ int shift, rm, rt, rd, rn, imm, sf, idx, option, scale, amount;
+ int sign_ext;
int rm_absent;
/* Initialize defaults, all are 0 except SF indicating 64bit access */
- shift = rd = rm = rn = imm = 0;
+ shift = rd = rm = rn = imm = idx = option = amount = scale = 0;
+ sign_ext = 0;
sf = 1;
matchp = 0;
@@ -278,14 +362,31 @@
if (matchp == 0)
goto undefined;
+ /* Global options */
+ if (i_ptr->special_ops & OP_SF32)
+ sf = 0;
+
+ /* Global optional tokens */
+ arm64_disasm_read_token(i_ptr, insn, "SF", &sf);
+ if (i_ptr->special_ops & OP_SF_INV)
+ sf = 1 - sf;
+ if (arm64_disasm_read_token(i_ptr, insn, "SIGN", &sign_ext) == 0)
+ sign_ext = 1 - sign_ext;
+ if (i_ptr->special_ops & OP_SIGN_EXT)
+ sign_ext = 1;
+ if (sign_ext != 0)
+ arm64_disasm_read_token_sign_ext(i_ptr, insn, "IMM", &imm);
+ else
+ arm64_disasm_read_token(i_ptr, insn, "IMM", &imm);
+
+ /* Print opcode by type */
switch (i_ptr->type) {
case TYPE_01:
/* OP <RD>, <RN>, <RM>{, <shift [LSL, LSR, ASR]> #<imm>} SF32/64
OP <RD>, <RN>, #<imm>{, <shift [0, 12]>} SF32/64 */
/* Mandatory tokens */
- ret = arm64_disasm_read_token(i_ptr, insn, "SF", &sf);
- ret |= arm64_disasm_read_token(i_ptr, insn, "RD", &rd);
+ ret = arm64_disasm_read_token(i_ptr, insn, "RD", &rd);
ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn);
if (ret != 0) {
printf("ERROR: Missing mandatory token for op %s type %d\n",
@@ -294,7 +395,6 @@
}
/* Optional tokens */
- arm64_disasm_read_token(i_ptr, insn, "IMM", &imm);
arm64_disasm_read_token(i_ptr, insn, "SHIFT", &shift);
rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm);
@@ -313,6 +413,124 @@
di->di_printf(" LSL #12");
}
break;
+ case TYPE_02:
+ /* OP <RT>, [<RN>, #<imm>]{!}] SF32/64
+ OP <RT>, [<RN>], #<imm>{!} SF32/64
+ OP <RT>, <RN>, <RM> {, EXTEND AMOUNT } */
+
+ /* Mandatory tokens */
+ ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt);
+ ret |= arm64_disasm_read_token(i_ptr, insn, "RN", &rn);
+ if (ret != 0) {
+ printf("ERROR: Missing mandatory token for op %s type %d\n",
+ i_ptr->name, i_ptr->type);
+ goto undefined;
+ }
+
+ /* Optional tokens */
+ arm64_disasm_read_token(i_ptr, insn, "OPTION", &option);
+ arm64_disasm_read_token(i_ptr, insn, "SCALE", &scale);
+ rm_absent = arm64_disasm_read_token(i_ptr, insn, "RM", &rm);
+
+ if (rm_absent) {
+ /* Indicate if immediate should be outside or inside brackets */
+ int inside;
+ /* Print exclamation mark if pre-incremented */
+ int pre;
+
+ /*
+ * In unsigned operation, shift immediate value
+ * and reset options to default.
+ */
+ if (sign_ext == 0) {
+ imm = imm << ((insn >> ARM_INSN_SIZE_OFFSET) &
+ ARM_INSN_SIZE_MASK);
+ option = 0;
+ }
+ switch (option) {
+ case 0x0:
+ pre = 0;
+ inside = 1;
+ break;
+ case 0x1:
+ pre = 0;
+ inside = 0;
+ break;
+ case 0x2:
+ pre = 1;
+ inside = 1;
+ default:
+ pre = 1;
+ inside = 1;
+ }
+
+ di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt));
+ if (inside != 0) {
+ di->di_printf("[%s", arm64_reg(1, rn));
+ if (imm != 0)
+ di->di_printf(", #%d", imm);
+ di->di_printf("]");
+ } else {
+ di->di_printf("[%s]", arm64_reg(1, rn));
+ if (imm != 0)
+ di->di_printf(", #%d", imm);
+ }
+ if (pre != 0)
+ di->di_printf("!");
+ } else {
+ /* Last bit of option field determines 32/64 bit offset */
+ di->di_printf("%s\t%s, [%s, %s", i_ptr->name,
+ arm64_reg(sf, rt), arm64_reg(1, rn),
+ arm64_reg(option & 1, rm));
+
+ /* Calculate amount, it's op(31:30) */
+ amount = (insn >> ARM_INSN_SIZE_OFFSET) &
+ ARM_INSN_SIZE_MASK;
+
+ switch (option) {
+ case 0x2:
+ di->di_printf(", uxtw #%d", amount);
+ break;
+ case 0x3:
+ if (scale != 0)
+ di->di_printf(", lsl #%d", amount);
+ break;
+ case 0x6:
+ di->di_printf(", sxtw #%d", amount);
+ break;
+ case 0x7:
+ di->di_printf(", sxts #%d", amount);
+ break;
+ default:
+ di->di_printf(", RSVD");
+ break;
+ }
+ di->di_printf("]");
+ }
+
+ break;
+
+ case TYPE_03:
+ /* OP <RT>, #imm SF32/64 */
+
+ /* Mandatory tokens */
+ ret = arm64_disasm_read_token(i_ptr, insn, "RT", &rt);
+ if (ret != 0) {
+ printf("ERROR: Missing mandatory token for op %s type %d\n",
+ i_ptr->name, i_ptr->type);
+ goto undefined;
+ }
+
+ if (i_ptr->special_ops & OP_MULT_4)
+ imm = imm << 2;
+
+ di->di_printf("%s\t%s, ", i_ptr->name, arm64_reg(sf, rt));
+ if (i_ptr->special_ops & OP_LITERAL)
+ di->di_printf("0x%lx", loc + imm);
+ else
+ di->di_printf("#%d", imm);
+
+ break;
default:
goto undefined;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 22, 10:43 PM (17 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32001923
Default Alt Text
D5217.id13087.diff (9 KB)
Attached To
Mode
D5217: ARM64 disassembler: support for LDRxx instructions
Attached
Detach File
Event Timeline
Log In to Comment