Rizin
unix-like reverse engineering framework and cli tools
mipsasm.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2012-2018 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_types.h>
5 #include <rz_util.h>
6 
7 static const char *const regs[33] = {
8  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
9  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
10  "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
11  "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
12  NULL
13 };
14 
15 static struct {
16  const char *name;
17  int type;
18  int args;
19  int n;
20  int x;
21 } ops[] = {
22  { "nop", 'N', 0, 0, 0 },
23  { "lui", 'I', 2, 15, 0 },
24  { "sw", 'I', 3, 43, 0 },
25  { "sh", 'I', 3, 41, 0 },
26  { "sb", 'I', 3, 40, 0 },
27  { "lw", 'I', 3, 35, 0 },
28  { "lh", 'I', 3, 33, 0 },
29  { "lb", 'I', 3, 32, 0 },
30  { "ori", 'I', 3, 13, 0 },
31  { "andi", 'I', 3, 12, 0 },
32  { "xori", 'I', 3, 14, 0 },
33  { "addi", 'I', 3, 8, 0 },
34  { "addiu", 'I', 3, 9, 0 },
35  { "b", 'B', -1, 4, 0 },
36  { "bnez", 'B', 2, 5, 0 },
37  { "bal", 'B', -1, -1, 17 },
38  { "bne", 'B', 3, 5, 0 },
39  { "beq", 'B', 3, 4, 0 },
40  { "bgez", 'B', -2, -1, 1 },
41  { "bgezal", 'B', -2, -1, 17 },
42  { "bltzal", 'B', -2, -1, 16 },
43  { "bgtz", 'B', -2, 7, 0 },
44  { "blez", 'B', -2, 6, 0 },
45  { "bltz", 'B', -2, 1, 0 },
46  { "syscall", 'R', 0, 12, 0 },
47  { "break", 'R', 0, 13, 0 },
48  { "nor", 'R', 3, 39, 0 },
49  { "or", 'R', 3, 37, 0 },
50  { "xor", 'R', 3, 38, 0 },
51  { "and", 'R', 3, 36, 0 },
52  { "sll", 'R', -3, 0, 0 },
53  { "sllv", 'R', 3, 4, 0 },
54  { "slt", 'R', 3, 42, 0 },
55  { "sltu", 'R', 3, 43, 0 },
56  { "sra", 'R', -3, 3, 0 },
57  { "srl", 'R', -3, 2, 0 },
58  { "srlv", 'R', 3, 6, 0 },
59  { "srav", 'R', 3, 7, 0 },
60  { "add", 'R', 3, 32, 0 },
61  { "move", 'R', -2, 32, 0 },
62  { "addu", 'R', 3, 33, 0 },
63  { "sub", 'R', 3, 34, 0 },
64  { "subu", 'R', 3, 35, 0 },
65  { "mult", 'R', 2, 24, 0 },
66  { "multu", 'R', 2, 25, 0 },
67  { "div", 'R', 2, 26, 0 },
68  { "divu", 'R', 2, 27, 0 },
69  { "mfhi", 'R', 1, 16, 0 },
70  { "mflo", 'R', 1, 18, 0 },
71  { "mthi", 'R', 1, 17, 0 },
72  { "mtlo", 'R', 1, 19, 0 },
73  { "jalr", 'R', -2, 9, 0 },
74  { "jr", 'R', 1, 8, 0 },
75  { "jal", 'J', 1, 3, 0 },
76  { "j", 'J', 1, 2, 0 },
77  { NULL }
78 };
79 
80 static int mips_r(ut8 *b, int op, int rs, int rt, int rd, int sa, int fun) {
81  //^this will keep the below mips_r fuctions working
82  // diff instructions use a diff arg order (add is rd, rs, rt - sll is rd, rt, sa - sllv is rd, rt, rs
83  // static int mips_r (ut8 *b, int op, int rd, int rs, int rt, int sa, int fun) {
84  if (rs < 0 || rt < 0 || rd < 0 || sa < 0) {
85  return -1;
86  }
87  b[3] = ((op << 2) & 0xfc) | ((rs >> 3) & 3); // 2
88  b[2] = (rs << 5) | (rt & 0x1f); // 1
89  b[1] = ((rd << 3) & 0xff) | (sa >> 2); // 0
90  b[0] = (fun & 0x3f) | ((sa & 3) << 6);
91  return 4;
92 }
93 
94 static int mips_i(ut8 *b, int op, int rs, int rt, int imm, int is_branch) {
95  if (rs < 0 || rt < 0) {
96  return -1;
97  }
98  if (is_branch) {
99  if (imm > 4) {
100  imm /= 4;
101  imm--;
102  } else {
103  imm = 0;
104  }
105  }
106  b[3] = ((op << 2) & 0xfc) | ((rs >> 3) & 3);
107  b[2] = (rs << 5) | (rt);
108  b[1] = (imm >> 8) & 0xff;
109  b[0] = imm & 0xff;
110  return 4;
111 }
112 
113 static int mips_j(ut8 *b, int op, int addr) {
114  addr /= 4;
115  b[3] = ((op << 2) & 0xfc) | ((addr >> 24) & 3);
116  b[2] = (addr >> 16) & 0xff;
117  b[1] = (addr >> 8) & 0xff;
118  b[0] = addr & 0xff;
119  return 4;
120 }
121 
122 static int getreg(const char *p) {
123  int n;
124  if (RZ_STR_ISEMPTY(p)) {
125  RZ_LOG_ERROR("assembler: mips: invalid assembly (missing an argument).\n");
126  return -1;
127  }
128  /* check if it's a register */
129  for (n = 0; regs[n]; n++) {
130  if (!strcmp(p, regs[n])) {
131  return n;
132  }
133  }
134  /* try to convert it into a number */
135  if (p[0] == '-') {
136  n = (int)rz_num_get(NULL, &p[1]);
137  n = -n;
138  } else {
139  n = (int)rz_num_get(NULL, p);
140  }
141  if (n != 0 || p[0] == '0') {
142  return n;
143  }
144  RZ_LOG_ERROR("assembler: mips: invalid reg name (%s) at pos %d.\n", p, n);
145  return -1;
146 }
147 
148 RZ_IPI int mips_assemble(const char *str, ut64 pc, ut8 *out) {
149  int i, hasp;
150  char w0[32], w1[32], w2[32], w3[32];
151  char *s = strdup(str);
152  if (!s) {
153  return -1;
154  }
155 
156  rz_str_replace_char(s, ',', ' ');
157  hasp = rz_str_replace_char(s, '(', ' ');
158  rz_str_replace_char(s, ')', ' ');
159 
160  *out = 0;
161  *w0 = 0;
162  *w1 = 0;
163  *w2 = 0;
164  *w3 = 0;
165 
166  if (!strncmp(s, "jalr", 4) && !strchr(s, ',')) {
167  char opstr[32];
168  const char *arg = strchr(s, ' ');
169  if (arg) {
170  snprintf(opstr, sizeof(opstr), "jalr ra ra %s", arg + 1);
171  free(s);
172  s = strdup(opstr);
173  if (!s) {
174  return -1;
175  }
176  }
177  }
178 
179  sscanf(s, "%31s", w0);
180  if (*w0) {
181  for (i = 0; ops[i].name; i++) {
182  if (!strcmp(ops[i].name, w0)) {
183  switch (ops[i].args) {
184  case 3: sscanf(s, "%31s %31s %31s %31s", w0, w1, w2, w3); break;
185  case -3: sscanf(s, "%31s %31s %31s %31s", w0, w1, w2, w3); break;
186  case 2: sscanf(s, "%31s %31s %31s", w0, w1, w2); break;
187  case -2: sscanf(s, "%31s %31s %31s", w0, w1, w2); break;
188  case 1: sscanf(s, "%31s %31s", w0, w1); break;
189  case -1: sscanf(s, "%31s %31s", w0, w1); break;
190  case 0: sscanf(s, "%31s", w0); break;
191  }
192  if (hasp) {
193  char tmp[32];
194  strcpy(tmp, w2);
195  strcpy(w2, w3);
196  strcpy(w3, tmp);
197  }
198  switch (ops[i].type) {
199  case 'R': {
200  // reg order diff per instruction 'group' - ordered to number of likelyhood to call (add > mfhi)
201  int op = 0, rs = 0, rt = 0, rd = 0, sa = 0, fn = 0;
202  bool invalid = false;
203  switch (ops[i].args) {
204  case 3:
205  rs = getreg(w2);
206  rt = getreg(w3);
207  rd = getreg(w1);
208  fn = ops[i].n;
209  break;
210  case -3:
211  if (ops[i].n > -1) {
212  rt = getreg(w2);
213  rd = getreg(w1);
214  sa = getreg(w3);
215  fn = ops[i].n;
216  } else {
217  rs = getreg(w3);
218  rt = getreg(w2);
219  rd = getreg(w1);
220  fn = (-1 * ops[i].n);
221  }
222  break;
223  case 2:
224  rs = getreg(w1);
225  rt = getreg(w2);
226  fn = ops[i].n;
227  break;
228  case 1:
229  rs = getreg(w1);
230  fn = ops[i].n;
231  break;
232  case -2:
233  rs = getreg(w2);
234  rd = getreg(w1);
235  fn = ops[i].n;
236  break;
237  case -1:
238  rd = getreg(w1);
239  fn = ops[i].n;
240  break;
241  case 0:
242  fn = ops[i].n;
243  break;
244  default:
245  invalid = true;
246  break;
247  }
248  if (!invalid) {
249  free(s);
250  return mips_r(out, op, rs, rt, rd, sa, fn);
251  }
252  break;
253  }
254  case 'I':
255  case 'B': {
256  bool invalid = false;
257  int op = 0, rs = 0, rt = 0, imm = 0, is_branch = ops[i].type == 'B';
258  switch (ops[i].args) {
259  case 2:
260  op = ops[i].n;
261  rt = getreg(w1);
262  imm = getreg(w2);
263  break;
264  case 3:
265  op = ops[i].n;
266  rs = getreg(w2);
267  rt = getreg(w1);
268  imm = getreg(w3);
269  break;
270  case -2:
271  if (ops[i].n > 0) {
272  op = ops[i].n;
273  rs = getreg(w1);
274  imm = getreg(w2);
275  } else {
276  op = (-1 * ops[i].n);
277  rs = getreg(w1);
278  rt = ops[i].x;
279  imm = getreg(w2);
280  }
281  break;
282  case -1:
283  if (ops[i].n > 0) {
284  op = ops[i].n;
285  imm = getreg(w1);
286  } else {
287  op = (-1 * ops[i].n);
288  rt = ops[i].x;
289  imm = getreg(w1);
290  }
291  break;
292  default:
293  invalid = true;
294  break;
295  }
296  if (!invalid) {
297  free(s);
298  return mips_i(out, op, rs, rt, imm, is_branch);
299  }
300  break;
301  }
302  case 'J':
303  if (ops[i].args == 1) {
304  free(s);
305  return mips_j(out, ops[i].n, getreg(w1));
306  }
307  break;
308  case 'N': // nop
309  memset(out, 0, 4);
310  free(s);
311  return 4;
312  }
313  free(s);
314  return -1;
315  }
316  }
317  }
318  free(s);
319  return -1;
320 }
#define rs()
#define rd()
#define imm
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
static int opstr(RzAsm *a, ut8 *data, const Opcode *op)
Definition: asm_x86_nz.c:4054
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
void * p
Definition: libc.cpp:67
static const char struct stat static buf struct stat static buf static idle const char static path static fd const char static len const void static prot const char struct module static image struct kernel_sym static table unsigned char static buf static fsuid unsigned struct dirent unsigned static count const struct iovec static count static pid const void static len static flags const struct sched_param static p static pid static policy struct timespec static tp static suid unsigned fn
Definition: sflib.h:186
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static const char *const regs[33]
Definition: mipsasm.c:7
static int mips_r(ut8 *b, int op, int rs, int rt, int rd, int sa, int fun)
Definition: mipsasm.c:80
int args
Definition: mipsasm.c:18
RZ_IPI int mips_assemble(const char *str, ut64 pc, ut8 *out)
Definition: mipsasm.c:148
static struct @104 ops[]
int x
Definition: mipsasm.c:20
int n
Definition: mipsasm.c:19
const char * name
Definition: mipsasm.c:16
static int getreg(const char *p)
Definition: mipsasm.c:122
static int mips_j(ut8 *b, int op, int addr)
Definition: mipsasm.c:113
int type
Definition: mipsasm.c:17
static int mips_i(ut8 *b, int op, int rs, int rt, int imm, int is_branch)
Definition: mipsasm.c:94
def is_branch(insn)
static RzSocket * s
Definition: rtr.c:28
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API ut64 rz_num_get(RzNum *num, const char *str)
Definition: unum.c:172
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
static int
Definition: sfsocketcall.h:114
#define b(i)
Definition: sha256.c:42
Definition: z80asm.h:102
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58