Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/tools/ido5.3_recomp/recomp.cpp
7858 views
1
#include <assert.h>
2
#include <stdint.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include <inttypes.h>
6
7
#include <algorithm>
8
#include <map>
9
#include <set>
10
#include <vector>
11
#include <string>
12
13
#include <capstone.h>
14
15
#include "elf.h"
16
17
#define INSPECT_FUNCTION_POINTERS 0 // set this to 1 when testing a new program, to verify that no false function pointers are found
18
19
#ifndef TRACE
20
#define TRACE 0
21
#endif
22
23
#define LABELS_64_BIT 1
24
25
#define u32be(x) (uint32_t)(((x & 0xff) << 24) + ((x & 0xff00) << 8) + ((x & 0xff0000) >> 8) + ((uint32_t)(x) >> 24))
26
#define u16be(x) (uint16_t)(((x & 0xff) << 8) + ((x & 0xff00) >> 8))
27
#define read_u32_be(buf) (uint32_t)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3]))
28
29
using namespace std;
30
31
struct Edge {
32
uint32_t i;
33
uint8_t function_entry: 1;
34
uint8_t function_exit: 1;
35
uint8_t extern_function: 1;
36
uint8_t function_pointer: 1;
37
};
38
39
struct Insn {
40
uint32_t id;
41
uint8_t op_count;
42
string mnemonic;
43
string op_str;
44
cs_mips_op operands[8];
45
46
uint8_t is_jump: 1;
47
uint8_t is_global_got_memop: 1;
48
uint8_t no_following_successor: 1;
49
int linked_insn;
50
union {
51
uint32_t linked_value;
52
float linked_float;
53
};
54
uint32_t jtbl_addr;
55
uint32_t num_cases;
56
mips_reg index_reg;
57
vector<Edge> successors;
58
vector<Edge> predecessors;
59
uint64_t b_liveout;
60
uint64_t b_livein;
61
uint64_t f_livein;
62
uint64_t f_liveout;
63
};
64
65
struct Function {
66
vector<uint32_t> returns; //points to delay slots
67
uint32_t end_addr; //address after end
68
uint32_t nargs;
69
uint32_t nret;
70
bool v0_in;
71
bool referenced_by_function_pointer;
72
};
73
74
static bool conservative;
75
76
static csh handle;
77
78
static const uint8_t *text_section;
79
static uint32_t text_section_len;
80
static uint32_t text_vaddr;
81
82
static const uint8_t *rodata_section;
83
static uint32_t rodata_section_len;
84
static uint32_t rodata_vaddr;
85
86
static const uint8_t *data_section;
87
static uint32_t data_section_len;
88
static uint32_t data_vaddr;
89
90
static uint32_t bss_section_len;
91
static uint32_t bss_vaddr;
92
93
static vector<Insn> insns;
94
static set<uint32_t> label_addresses;
95
static vector<uint32_t> got_globals;
96
static vector<uint32_t> got_locals;
97
static uint32_t gp_value;
98
static uint32_t gp_value_adj;
99
100
static map<uint32_t, string> symbol_names;
101
102
static vector<pair<uint32_t, uint32_t>> data_function_pointers;
103
static set<uint32_t> li_function_pointers;
104
static map<uint32_t, Function> functions;
105
static uint32_t main_addr;
106
static uint32_t mcount_addr;
107
static uint32_t procedure_table_start;
108
static uint32_t procedure_table_len;
109
110
#define FLAG_NO_MEM 1
111
#define FLAG_VARARG 2
112
113
static const struct {
114
const char *name;
115
const char *params;
116
int flags;
117
} extern_functions[] = {
118
{"exit", "vi"}, // override exit from application
119
{"abort", "v"},
120
{"sbrk", "pi"},
121
{"malloc", "pu"},
122
{"calloc", "puu"},
123
{"realloc", "ppu"},
124
{"free", "vp"},
125
{"fscanf", "ipp", FLAG_VARARG},
126
{"printf", "ip", FLAG_VARARG},
127
{"sprintf", "ipp", FLAG_VARARG},
128
{"fprintf", "ipp", FLAG_VARARG},
129
{"_doprnt", "ippp"},
130
{"strlen", "up"},
131
{"open", "ipii"},
132
{"creat", "ipi"},
133
{"access", "ipi"},
134
{"rename", "ipp"},
135
{"utime", "ipp"},
136
{"flock", "iii"},
137
{"chmod", "ipu"},
138
{"umask", "ii", FLAG_NO_MEM},
139
{"ecvt", "pdipp"},
140
{"fcvt", "pdipp"},
141
{"sqrt", "dd", FLAG_NO_MEM},
142
{"sqrtf", "ff", FLAG_NO_MEM},
143
{"atoi", "ip"},
144
{"atol", "ip"},
145
{"atof", "dp"},
146
{"strtol", "ippi"},
147
{"strtoul", "uppi"},
148
{"strtod", "dpp"},
149
{"strchr", "ppi"},
150
{"strrchr", "ppi"},
151
{"strcspn", "upp"},
152
{"strpbrk", "ppp"},
153
{"fstat", "iip"},
154
{"stat", "ipp"},
155
{"ftruncate", "iii"},
156
{"bcopy", "vppu"},
157
{"memcpy", "pppu"},
158
{"memccpy", "pppiu"},
159
{"read", "iipu"},
160
{"write", "iipu"},
161
{"fopen", "ppp"},
162
{"freopen", "pppp"},
163
{"fclose", "ip"},
164
{"ftell", "ip"},
165
{"rewind", "vp"},
166
{"fseek", "ipii"},
167
{"lseek", "iiii"},
168
{"fflush", "ip"},
169
{"dup", "ii"},
170
{"dup2", "iii"},
171
{"pipe", "ip"},
172
{"perror", "vp"},
173
{"fdopen", "iip"},
174
{"memset", "ppiu"},
175
{"bcmp", "ippu"},
176
{"memcmp", "ippu"},
177
{"getpid", "i", FLAG_NO_MEM},
178
{"getpgrp", "i"},
179
{"remove", "ip"},
180
{"unlink", "ip"},
181
{"close", "ii"},
182
{"strcmp", "ipp"},
183
{"strncmp", "ippu"},
184
{"strcpy", "ppp"},
185
{"strncpy", "pppu"},
186
{"strcat", "ppp"},
187
{"strncat", "pppu"},
188
{"strtok", "ppp"},
189
{"strstr", "ppp"},
190
{"strdup", "pp"},
191
{"toupper", "ii", FLAG_NO_MEM},
192
{"tolower", "ii", FLAG_NO_MEM},
193
{"gethostname", "ipu"},
194
{"isatty", "ii"},
195
{"strftime", "upupp"},
196
{"times", "ip"},
197
{"clock", "i", FLAG_NO_MEM},
198
{"ctime", "pp"},
199
{"localtime", "pp"},
200
{"setvbuf", "ippiu"},
201
{"__semgetc", "ip"},
202
{"__semputc", "iip"},
203
{"fgetc", "ip"},
204
{"fgets", "ipip"},
205
{"__filbuf", "ip"},
206
{"__flsbuf", "iip"},
207
{"ungetc", "iip"},
208
{"gets", "pp"},
209
{"fread", "upuup"},
210
{"fwrite", "upuup"},
211
{"fputs", "ipp"},
212
{"puts", "ip"},
213
{"getcwd", "ppu"},
214
{"time", "ip"},
215
{"bzero", "vpu"},
216
{"fp_class_d", "id", FLAG_NO_MEM},
217
{"ldexp", "ddi", FLAG_NO_MEM},
218
{"__ll_mul", "lll", FLAG_NO_MEM},
219
{"__ll_div", "lll", FLAG_NO_MEM},
220
{"__ll_rem", "ljl", FLAG_NO_MEM},
221
{"__ll_lshift", "llj", FLAG_NO_MEM},
222
{"__ll_rshift", "llj", FLAG_NO_MEM},
223
{"__ull_div", "jjj", FLAG_NO_MEM},
224
{"__ull_rem", "jjj", FLAG_NO_MEM},
225
{"__ull_rshift", "jjj", FLAG_NO_MEM},
226
{"__d_to_ull", "jd", FLAG_NO_MEM},
227
{"__d_to_ll", "ld", FLAG_NO_MEM},
228
{"__f_to_ull", "jf", FLAG_NO_MEM},
229
{"__f_to_ll", "lf", FLAG_NO_MEM},
230
{"__ull_to_f", "fj", FLAG_NO_MEM},
231
{"__ll_to_f", "fl", FLAG_NO_MEM},
232
{"__ull_to_d", "dj", FLAG_NO_MEM},
233
{"__ll_to_d", "dl", FLAG_NO_MEM},
234
{"_exit", "vi"},
235
{"_cleanup", "v"},
236
{"_rld_new_interface", "pu", FLAG_VARARG},
237
{"_exithandle", "v"},
238
{"_prctl", "ii", FLAG_VARARG},
239
{"_atod", "dpii"},
240
{"pathconf", "ipi"},
241
{"getenv", "pp"},
242
{"gettxt", "ppp"},
243
{"setlocale", "pip"},
244
{"mmap", "ppuiiii"},
245
{"munmap", "ipu"},
246
{"mprotect", "ipui"},
247
{"sysconf", "ii"},
248
{"getpagesize", "i"},
249
{"strerror", "pi"},
250
{"ioctl", "iiu", FLAG_VARARG},
251
{"fcntl", "iii", FLAG_VARARG},
252
{"signal", "pit"},
253
{"sigset", "pit"},
254
{"get_fpc_csr", "i"},
255
{"set_fpc_csr", "ii"},
256
{"setjmp", "ip"},
257
{"longjmp", "vpi"},
258
{"tempnam", "ppp"},
259
{"tmpnam", "pp"},
260
{"mktemp", "pp"},
261
{"mkstemp", "ip"},
262
{"tmpfile", "p"},
263
{"wait", "ip"},
264
{"kill", "iii"},
265
{"execlp", "ip", FLAG_VARARG},
266
{"execv", "ipp"},
267
{"execvp", "ipp"},
268
{"fork", "i"},
269
{"system", "ip"},
270
{"tsearch", "pppp"},
271
{"tfind", "pppp"},
272
{"qsort", "vpuut"},
273
{"regcmp", "pp", FLAG_VARARG},
274
{"regex", "ppp", FLAG_VARARG},
275
{"__assert", "vppi"},
276
};
277
278
static void disassemble(void) {
279
csh handle;
280
cs_insn *disasm;
281
size_t disasm_size = 0;
282
assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK);
283
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
284
insns.reserve(1 + text_section_len / sizeof(uint32_t)); // +1 for dummy instruction
285
while (text_section_len > disasm_size * sizeof(uint32_t)) {
286
size_t disasm_len = disasm_size * sizeof(uint32_t);
287
size_t remaining = text_section_len - disasm_len;
288
size_t current_len = std::min<size_t>(remaining, 1024);
289
size_t cur_disasm_size = cs_disasm(handle, &text_section[disasm_len], current_len, text_vaddr + disasm_len, 0, &disasm);
290
disasm_size += cur_disasm_size;
291
for (size_t i = 0; i < cur_disasm_size; i++) {
292
insns.push_back(Insn());
293
Insn& insn = insns.back();
294
insn.id = disasm[i].id;
295
insn.mnemonic = disasm[i].mnemonic;
296
insn.op_str = disasm[i].op_str;
297
if (disasm[i].detail != nullptr && disasm[i].detail->mips.op_count > 0) {
298
insn.op_count = disasm[i].detail->mips.op_count;
299
memcpy(insn.operands, disasm[i].detail->mips.operands, sizeof(insn.operands));
300
}
301
insn.is_jump = cs_insn_group(handle, &disasm[i], MIPS_GRP_JUMP) || insn.id == MIPS_INS_JAL || insn.id == MIPS_INS_BAL || insn.id == MIPS_INS_JALR;
302
insn.linked_insn = -1;
303
}
304
cs_free(disasm, cur_disasm_size);
305
}
306
cs_close(&handle);
307
308
{
309
// Add dummy instruction to avoid out of bounds
310
insns.push_back(Insn());
311
Insn& insn = insns.back();
312
insn.id = MIPS_INS_NOP;
313
insn.mnemonic = "nop";
314
insn.no_following_successor = true;
315
}
316
}
317
318
static void add_function(uint32_t addr) {
319
if (addr >= text_vaddr && addr < text_vaddr + text_section_len) {
320
functions[addr];
321
}
322
}
323
324
static map<uint32_t, Function>::iterator find_function(uint32_t addr) {
325
if (functions.size() == 0) {
326
return functions.end();
327
}
328
auto it = functions.upper_bound(addr);
329
if (it == functions.begin()) {
330
return functions.end();
331
}
332
--it;
333
return it;
334
}
335
336
// try to find a matching LUI for a given register
337
static void link_with_lui(int offset, uint32_t reg, int mem_imm)
338
{
339
#define MAX_LOOKBACK 128
340
// don't attempt to compute addresses for zero offset
341
// end search after some sane max number of instructions
342
int end_search = std::max(0, offset - MAX_LOOKBACK);
343
for (int search = offset - 1; search >= end_search; search--) {
344
// use an `if` instead of `case` block to allow breaking out of the `for` loop
345
if (insns[search].id == MIPS_INS_LUI) {
346
uint32_t rd = insns[search].operands[0].reg;
347
if (reg == rd) {
348
break;
349
}
350
} else if (insns[search].id == MIPS_INS_LW ||
351
insns[search].id == MIPS_INS_LD ||
352
insns[search].id == MIPS_INS_ADDIU ||
353
//insns[search].id == MIPS_INS_ADDU || used in jump tables for offset
354
insns[search].id == MIPS_INS_ADD ||
355
insns[search].id == MIPS_INS_SUB ||
356
insns[search].id == MIPS_INS_SUBU) {
357
uint32_t rd = insns[search].operands[0].reg;
358
if (reg == rd) {
359
if (insns[search].id == MIPS_INS_LW && insns[search].operands[1].mem.base == MIPS_REG_GP) {
360
int mem_imm0 = (int)insns[search].operands[1].mem.disp;
361
uint32_t got_entry = (mem_imm0 + gp_value_adj) / sizeof(uint32_t);
362
if (got_entry < got_locals.size()) {
363
// used for static functions
364
char buf[32];
365
uint32_t addr = got_locals[got_entry] + mem_imm;
366
insns[search].linked_insn = offset;
367
insns[search].linked_value = addr;
368
insns[offset].linked_insn = search;
369
insns[offset].linked_value = addr;
370
371
//vaddr_references[addr].insert(text_vaddr + offset * 4);
372
373
insns[search].id = MIPS_INS_LI;
374
insns[search].mnemonic = "li";
375
sprintf(buf, "$%s, 0x%x", cs_reg_name(handle, rd), addr);
376
insns[search].op_str = buf;
377
insns[search].operands[1].type = MIPS_OP_IMM;
378
insns[search].operands[1].imm = addr;
379
380
switch (insns[offset].id) {
381
case MIPS_INS_ADDIU:
382
insns[offset].id = MIPS_INS_MOVE;
383
insns[offset].operands[1].type = MIPS_OP_REG;
384
insns[offset].mnemonic = "move";
385
sprintf(buf, "$%s, $%s", cs_reg_name(handle, insns[offset].operands[0].reg), cs_reg_name(handle, rd));
386
insns[offset].op_str = buf;
387
if (addr >= text_vaddr && addr < text_vaddr + text_section_len) {
388
add_function(addr);
389
}
390
break;
391
case MIPS_INS_LB:
392
case MIPS_INS_LBU:
393
case MIPS_INS_SB:
394
case MIPS_INS_LH:
395
case MIPS_INS_LHU:
396
case MIPS_INS_SH:
397
case MIPS_INS_LW:
398
case MIPS_INS_SW:
399
case MIPS_INS_LDC1:
400
case MIPS_INS_LWC1:
401
case MIPS_INS_SWC1:
402
insns[offset].operands[1].mem.disp = 0;
403
sprintf(buf, "$%s, ($%s)", cs_reg_name(handle, insns[offset].operands[0].reg), cs_reg_name(handle, rd));
404
insns[offset].op_str = buf;
405
break;
406
default:
407
assert(0);
408
}
409
}
410
break;
411
} else {
412
// ignore: reg is pointer, offset is probably struct data member
413
break;
414
}
415
}
416
} else if (insns[search].id == MIPS_INS_JR &&
417
insns[search].operands[0].reg == MIPS_REG_RA && offset - search >= 2) {
418
// stop looking when previous `jr ra` is hit,
419
// but ignore if `offset` is branch delay slot for this `jr ra`
420
break;
421
}
422
}
423
}
424
425
// for a given `jalr t9`, find the matching t9 load
426
static void link_with_jalr(int offset)
427
{
428
// end search after some sane max number of instructions
429
int end_search = std::max(0, offset - MAX_LOOKBACK);
430
for (int search = offset - 1; search >= end_search; search--) {
431
if (insns[search].operands[0].reg == MIPS_REG_T9) {
432
if (insns[search].id == MIPS_INS_LW || insns[search].id == MIPS_INS_LI) {
433
if (insns[search].is_global_got_memop || insns[search].id == MIPS_INS_LI) {
434
char buf[32];
435
sprintf(buf, "0x%x", insns[search].linked_value);
436
insns[search].linked_insn = offset;
437
insns[offset].linked_insn = search;
438
insns[offset].linked_value = insns[search].linked_value;
439
//insns[offset].label = insns[search].label;
440
//function_entry_points.insert(insns[search].linked_value);
441
insns[offset].id = MIPS_INS_JAL;
442
insns[offset].mnemonic = "jal";
443
insns[offset].op_str = buf;
444
insns[offset].operands[0].type = MIPS_OP_IMM;
445
insns[offset].operands[0].imm = insns[search].linked_value;
446
insns[search].id = MIPS_INS_NOP;
447
insns[search].mnemonic = "nop";
448
insns[search].op_str = "";
449
insns[search].is_global_got_memop = false;
450
add_function(insns[search].linked_value);
451
}
452
break;
453
} else if (insns[search].id == MIPS_INS_ADDIU) {
454
if (insns[search].linked_insn != -1) {
455
//function_entry_points.insert(insns[search].linked_value);
456
uint32_t first = insns[search].linked_insn;
457
insns[search].linked_insn = offset;
458
insns[offset].linked_insn = first;
459
insns[offset].linked_value = insns[search].linked_value;
460
}
461
break;
462
} else if (insns[search].id == MIPS_INS_LI) {
463
if (insns[search].linked_insn != -1) {
464
//function_entry_points.insert(insns[search].linked_value);
465
uint32_t first = insns[search].linked_insn;
466
insns[search].linked_insn = offset;
467
insns[offset].linked_insn = first;
468
insns[offset].linked_value = insns[search].linked_value;
469
insns[search].id = MIPS_INS_NOP;
470
insns[search].mnemonic = "nop";
471
insns[search].op_str = "";
472
}
473
break;
474
} else if (insns[search].id == MIPS_INS_LD ||
475
insns[search].id == MIPS_INS_ADDU ||
476
insns[search].id == MIPS_INS_ADD ||
477
insns[search].id == MIPS_INS_SUB ||
478
insns[search].id == MIPS_INS_SUBU) {
479
break;
480
}
481
} else if (insns[search].id == MIPS_INS_JR &&
482
insns[search].operands[0].reg == MIPS_REG_RA)
483
{
484
// stop looking when previous `jr ra` is hit
485
break;
486
}
487
}
488
}
489
490
static void pass1(void) {
491
for (size_t i = 0; i < insns.size(); i++) {
492
Insn& insn = insns[i];
493
if (insn.id == MIPS_INS_BAL) {
494
insn.id = MIPS_INS_JAL;
495
insn.mnemonic = "jal";
496
}
497
if (insn.is_jump) {
498
if (insn.id == MIPS_INS_JAL || insn.id == MIPS_INS_J) {
499
uint32_t target = (uint32_t)insn.operands[0].imm;
500
label_addresses.insert(target);
501
add_function(target);
502
} else if (insn.id == MIPS_INS_JR) {
503
// sltiu $at, $ty, z
504
// sw $reg, offset($sp) (very seldom, one or more, usually in func entry)
505
// lw $gp, offset($sp) (if PIC, and very seldom)
506
// beqz $at, .L
507
// some other instruction (not always)
508
// lui $at, %hi(jtbl)
509
// sll $tx, $ty, 2
510
// addu $at, $at, $tx
511
// lw $tx, %lo(jtbl)($at)
512
// nop (code compiled with 5.3)
513
// addu $tx, $tx, $gp (if PIC)
514
// jr $tx
515
516
// IDO 7.1:
517
//lw at,offset(gp)
518
//andi t9,t8,0x3f
519
//sll t9,t9,0x2
520
//addu at,at,t9
521
//lw t9,offset(at)
522
//addu t9,t9,gp
523
//jr t9
524
525
// IDO 5.3:
526
//lw at,offset(gp)
527
//andi t3,t2,0x3f
528
//sll t3,t3,0x2
529
//addu at,at,t3
530
//something
531
//lw t3,offset(at)
532
//something
533
//addu t3,t3,gp
534
//jr t3
535
if (i >= 7 && rodata_section != NULL) {
536
bool is_pic = insns[i - 1].id == MIPS_INS_ADDU && insns[i - 1].operands[2].reg == MIPS_REG_GP;
537
bool has_nop = insns[i - is_pic - 1].id == MIPS_INS_NOP;
538
bool has_extra = insns[i - is_pic - has_nop - 5].id != MIPS_INS_BEQZ;
539
int lw = i - is_pic - has_nop - 1;
540
if (insns[lw].id != MIPS_INS_LW) {
541
--lw;
542
}
543
if (insns[lw].id == MIPS_INS_LW && insns[lw].linked_insn != -1) {
544
int sltiu_index = -1;
545
int andi_index = -1;
546
uint32_t addu_index = lw - 1;
547
uint32_t num_cases;
548
bool found = false;
549
bool and_variant = false;
550
int end = 14;
551
if (insns[addu_index].id != MIPS_INS_ADDU) {
552
--addu_index;
553
}
554
mips_reg index_reg = (mips_reg)insns[addu_index - 1].operands[1].reg;
555
if (insns[addu_index].id != MIPS_INS_ADDU) {
556
goto skip;
557
}
558
if (insns[addu_index - 1].id != MIPS_INS_SLL) {
559
goto skip;
560
}
561
if (insns[addu_index - 1].operands[0].reg != insn.operands[0].reg) {
562
goto skip;
563
}
564
for (int j = 3; j <= 4; j++) {
565
if (insns[lw - j].id == MIPS_INS_ANDI) {
566
andi_index = lw - j;
567
break;
568
}
569
}
570
if (i == 368393) {
571
// In copt
572
end = 18;
573
}
574
for (int j = 5; j <= end; j++) {
575
if (insns[lw - has_extra - j].id == MIPS_INS_SLTIU &&
576
insns[lw - has_extra - j].operands[0].reg == MIPS_REG_AT)
577
{
578
sltiu_index = j;
579
break;
580
}
581
if (insns[lw - has_extra - j].id == MIPS_INS_JR) {
582
// Prevent going into a previous switch
583
break;
584
}
585
}
586
if (sltiu_index != -1) {
587
andi_index = -1;
588
}
589
if (sltiu_index != -1 && insns[lw - has_extra - sltiu_index].id == MIPS_INS_SLTIU) {
590
num_cases = insns[lw - has_extra - sltiu_index].operands[2].imm;
591
found = true;
592
} else if (andi_index != -1) {
593
num_cases = insns[andi_index].operands[2].imm + 1;
594
found = true;
595
and_variant = true;
596
} else if (i == 219382) {
597
// Special hard case in copt where the initial sltiu is in another basic block
598
found = true;
599
num_cases = 13;
600
} else if (i == 370995) {
601
// Special hard case in copt where the initial sltiu is in another basic block
602
found = true;
603
num_cases = 12;
604
}
605
if (found) {
606
uint32_t jtbl_addr = insns[lw].linked_value;
607
if (is_pic) {
608
insns[i - 1].id = MIPS_INS_NOP;
609
}
610
//printf("jump table at %08x, size %u\n", jtbl_addr, num_cases);
611
insn.jtbl_addr = jtbl_addr;
612
insn.num_cases = num_cases;
613
insn.index_reg = index_reg;
614
insns[lw].id = MIPS_INS_NOP;
615
insns[addu_index].id = MIPS_INS_NOP;
616
insns[addu_index - 1].id = MIPS_INS_NOP;
617
if (!and_variant) {
618
insns[addu_index - 2].id = MIPS_INS_NOP;
619
}
620
621
if (jtbl_addr < rodata_vaddr || jtbl_addr + num_cases * sizeof(uint32_t) > rodata_vaddr + rodata_section_len) {
622
fprintf(stderr, "jump table outside rodata\n");
623
exit(EXIT_FAILURE);
624
}
625
for (uint32_t i = 0; i < num_cases; i++) {
626
uint32_t target_addr = read_u32_be(rodata_section + (jtbl_addr - rodata_vaddr) + i * sizeof(uint32_t));
627
target_addr += gp_value;
628
//printf("%08X\n", target_addr);
629
label_addresses.insert(target_addr);
630
}
631
}
632
skip:;
633
}
634
}
635
} else {
636
for (int j = 0; j < insn.op_count; j++) {
637
if (insn.operands[j].type == MIPS_OP_IMM) {
638
uint32_t target = (uint32_t)insn.operands[j].imm;
639
label_addresses.insert(target);
640
}
641
}
642
}
643
}
644
switch (insns[i].id) {
645
// find floating point LI
646
case MIPS_INS_MTC1:
647
{
648
unsigned int rt = insns[i].operands[0].reg;
649
for (int s = i - 1; s >= 0; s--) {
650
if (insns[s].id == MIPS_INS_LUI && insns[s].operands[0].reg == rt) {
651
float f;
652
uint32_t lui_imm = (uint32_t)(insns[s].operands[1].imm << 16);
653
memcpy(&f, &lui_imm, sizeof(f));
654
insns[s].operands[1].imm <<= 16;
655
// link up the LUI with this instruction and the float
656
insns[s].linked_insn = i;
657
insns[s].linked_float = f;
658
// rewrite LUI instruction to be LI
659
insns[s].id = MIPS_INS_LI;
660
insns[s].mnemonic = "li";
661
break;
662
} else if (insns[s].id == MIPS_INS_LW ||
663
insns[s].id == MIPS_INS_LD ||
664
insns[s].id == MIPS_INS_LH ||
665
insns[s].id == MIPS_INS_LHU ||
666
insns[s].id == MIPS_INS_LB ||
667
insns[s].id == MIPS_INS_LBU ||
668
insns[s].id == MIPS_INS_ADDIU ||
669
insns[s].id == MIPS_INS_ADD ||
670
insns[s].id == MIPS_INS_SUB ||
671
insns[s].id == MIPS_INS_SUBU) {
672
unsigned int rd = insns[s].operands[0].reg;
673
if (rt == rd) {
674
break;
675
}
676
} else if (insns[s].id == MIPS_INS_JR &&
677
insns[s].operands[0].reg == MIPS_REG_RA) {
678
// stop looking when previous `jr ra` is hit
679
break;
680
}
681
}
682
break;
683
}
684
case MIPS_INS_SD:
685
case MIPS_INS_SW:
686
case MIPS_INS_SH:
687
case MIPS_INS_SB:
688
case MIPS_INS_LB:
689
case MIPS_INS_LBU:
690
case MIPS_INS_LD:
691
case MIPS_INS_LDL:
692
case MIPS_INS_LDR:
693
case MIPS_INS_LH:
694
case MIPS_INS_LHU:
695
case MIPS_INS_LW:
696
case MIPS_INS_LWU:
697
case MIPS_INS_LDC1:
698
case MIPS_INS_LWC1:
699
case MIPS_INS_LWC2:
700
case MIPS_INS_LWC3:
701
case MIPS_INS_SWC1:
702
case MIPS_INS_SWC2:
703
case MIPS_INS_SWC3:
704
{
705
unsigned int mem_rs = insns[i].operands[1].mem.base;
706
int mem_imm = (int)insns[i].operands[1].mem.disp;
707
if (mem_rs == MIPS_REG_GP) {
708
unsigned int got_entry = (mem_imm + gp_value_adj) / sizeof(unsigned int);
709
if (got_entry >= got_locals.size()) {
710
got_entry -= got_locals.size();
711
if (got_entry < got_globals.size()) {
712
assert(insn.id == MIPS_INS_LW);
713
//printf("gp 0x%08x %s\n", mem_imm, got_globals[got_entry].name);
714
unsigned int dest_vaddr = got_globals[got_entry];
715
insns[i].is_global_got_memop = true;
716
insns[i].linked_value = dest_vaddr;
717
//insns[i].label = got_globals[got_entry].name;
718
719
//vaddr_references[dest_vaddr].insert(vaddr + i * 4);
720
//disasm_add_data_addr(state, dest_vaddr);
721
insns[i].id = MIPS_INS_LI;
722
insns[i].operands[1].imm = dest_vaddr;
723
char buf[32];
724
sprintf(buf, "$%s, 0x%x", cs_reg_name(handle, insn.operands[0].reg), dest_vaddr);
725
insns[i].op_str = buf;
726
}
727
}
728
} else {
729
link_with_lui(i, mem_rs, mem_imm);
730
}
731
break;
732
}
733
case MIPS_INS_ADDIU:
734
case MIPS_INS_ORI:
735
{
736
unsigned int rd = insns[i].operands[0].reg;
737
unsigned int rs = insns[i].operands[1].reg;
738
int64_t imm = insns[i].operands[2].imm;
739
if (rs == MIPS_REG_ZERO) { // becomes LI
740
char buf[32];
741
insns[i].id = MIPS_INS_LI;
742
insns[i].operands[1].imm = imm;
743
insns[i].mnemonic = "li";
744
sprintf(buf, "$%s, %" PRIi64, cs_reg_name(handle, rd), imm);
745
insns[i].op_str = buf;
746
} else if (/*rd == rs &&*/ rd != MIPS_REG_GP) { // only look for LUI if rd and rs are the same
747
link_with_lui(i, rs, (int)imm);
748
}
749
break;
750
}
751
case MIPS_INS_JALR:
752
{
753
unsigned int r = insn.operands[0].reg;
754
if (r == MIPS_REG_T9) {
755
link_with_jalr(i);
756
if (insn.linked_insn != -1) {
757
char buf[32];
758
sprintf(buf, "0x%x", insn.linked_value);
759
insn.id = MIPS_INS_JAL;
760
insn.mnemonic = "jal";
761
insn.op_str = buf;
762
insn.operands[0].type = MIPS_OP_IMM;
763
insn.operands[0].imm = insn.linked_value;
764
label_addresses.insert(insn.linked_value);
765
add_function(insn.linked_value);
766
}
767
}
768
break;
769
}
770
}
771
if (insn.id == MIPS_INS_ADDU && insn.operands[0].reg == MIPS_REG_GP && insn.operands[1].reg == MIPS_REG_GP && insn.operands[2].reg == MIPS_REG_T9 && i >= 2) {
772
//state->function_entry_points.insert(vaddr + (i - 2) * 4);
773
for (int j = i - 2; j <= i; j++) {
774
insns[j].id = MIPS_INS_NOP;
775
insns[j].mnemonic = "nop";
776
insns[j].op_str = "";
777
}
778
}
779
}
780
}
781
782
static uint32_t addr_to_i(uint32_t addr) {
783
return (addr - text_vaddr) / 4;
784
}
785
786
static void pass2(void) {
787
// Find returns in each function
788
for (size_t i = 0; i < insns.size(); i++) {
789
uint32_t addr = text_vaddr + i * 4;
790
Insn& insn = insns[i];
791
if (insn.id == MIPS_INS_JR && insn.operands[0].reg == MIPS_REG_RA) {
792
auto it = find_function(addr);
793
assert(it != functions.end());
794
it->second.returns.push_back(addr + 4);
795
}
796
if (insn.is_global_got_memop && text_vaddr <= insn.operands[1].imm && insn.operands[1].imm < text_vaddr + text_section_len) {
797
uint32_t faddr = insn.operands[1].imm;
798
li_function_pointers.insert(faddr);
799
functions[faddr].referenced_by_function_pointer = true;
800
#if INSPECT_FUNCTION_POINTERS
801
fprintf(stderr, "li function pointer: 0x%x at 0x%x\n", faddr, addr);
802
#endif
803
}
804
}
805
for (auto it = functions.begin(); it != functions.end(); ++it) {
806
if (it->second.returns.size() == 0) {
807
uint32_t i = addr_to_i(it->first);
808
auto str_it = symbol_names.find(it->first);
809
if (str_it != symbol_names.end() && str_it->second == "__start") {
810
811
} else if (str_it != symbol_names.end() && str_it->second == "xmalloc") {
812
// orig 5.3:
813
/*
814
496bf4: 3c1c0fb9 lui gp,0xfb9
815
496bf8: 279c366c addiu gp,gp,13932
816
496bfc: 0399e021 addu gp,gp,t9
817
496c00: 27bdffd8 addiu sp,sp,-40
818
496c04: 8f858de8 lw a1,-29208(gp)
819
496c08: 10000006 b 496c24 <alloc_new+0x14>
820
496c0c: afbf0020 sw ra,32(sp)
821
*/
822
823
// jal alloc_new
824
// lui $a1, malloc_scb
825
// jr $ra
826
// nop
827
uint32_t alloc_new_addr = text_vaddr + (i + 7) * 4;
828
insns[i].id = MIPS_INS_JAL;
829
insns[i].op_count = 1;
830
insns[i].mnemonic = "jal";
831
insns[i].op_str = "alloc_new";
832
insns[i].operands[0].imm = alloc_new_addr;
833
assert(symbol_names.count(alloc_new_addr) && symbol_names[alloc_new_addr] == "alloc_new");
834
i++;
835
if (insns[i + 5].id == MIPS_INS_LI) {
836
// 7.1
837
insns[i] = insns[i + 5];
838
} else {
839
// 5.3
840
insns[i] = insns[i + 3];
841
}
842
i++;
843
insns[i].id = MIPS_INS_JR;
844
insns[i].op_count = 1;
845
insns[i].mnemonic = "jr";
846
insns[i].op_str = "$ra";
847
insns[i].operands[0].reg = MIPS_REG_RA;
848
it->second.returns.push_back(text_vaddr + i * 4 + 4);
849
i++;
850
for (uint32_t j = 0; j < 4; j++) {
851
insns[i].id = MIPS_INS_NOP;
852
insns[i].op_count = 0;
853
insns[i].mnemonic = "nop";
854
i++;
855
}
856
} else if (str_it != symbol_names.end() && str_it->second == "xfree") {
857
// jal alloc_dispose
858
// lui $a1, malloc_scb
859
// jr $ra
860
// nop
861
uint32_t alloc_dispose_addr = text_vaddr + (i + 4) * 4;
862
if (symbol_names.count(alloc_dispose_addr + 4) && symbol_names[alloc_dispose_addr + 4] == "alloc_dispose") {
863
alloc_dispose_addr += 4;
864
}
865
insns[i].id = MIPS_INS_JAL;
866
insns[i].op_count = 1;
867
insns[i].mnemonic = "jal";
868
insns[i].op_str = "alloc_dispose";
869
insns[i].operands[0].imm = alloc_dispose_addr;
870
assert(symbol_names.count(alloc_dispose_addr) && symbol_names[alloc_dispose_addr] == "alloc_dispose");
871
i++;
872
insns[i] = insns[i + 2];
873
i++;
874
insns[i].id = MIPS_INS_JR;
875
insns[i].op_count = 1;
876
insns[i].mnemonic = "jr";
877
insns[i].op_str = "$ra";
878
insns[i].operands[0].reg = MIPS_REG_RA;
879
it->second.returns.push_back(text_vaddr + i * 4 + 4);
880
i++;
881
insns[i].id = MIPS_INS_NOP;
882
insns[i].op_count = 0;
883
insns[i].mnemonic = "nop";
884
} else if (insns[i].id == MIPS_INS_LW && insns[i + 1].id == MIPS_INS_MOVE && insns[i + 2].id == MIPS_INS_JALR) {
885
/*
886
408f50: 8f998010 lw t9,-32752(gp)
887
408f54: 03e07821 move t7,ra
888
408f58: 0320f809 jalr t9
889
*/
890
} else if (it->first > mcount_addr) {
891
fprintf(stderr, "no ret: 0x%x\n", it->first);
892
abort();
893
}
894
}
895
auto next = it;
896
++next;
897
if (next == functions.end()) {
898
it->second.end_addr = text_vaddr + text_section_len;
899
} else {
900
it->second.end_addr = next->first;
901
}
902
}
903
}
904
905
static void add_edge(uint32_t from, uint32_t to, bool function_entry = false, bool function_exit = false, bool extern_function = false, bool function_pointer = false) {
906
Edge fe = Edge(), be = Edge();
907
fe.i = to;
908
be.i = from;
909
fe.function_entry = function_entry;
910
be.function_entry = function_entry;
911
fe.function_exit = function_exit;
912
be.function_exit = function_exit;
913
fe.extern_function = extern_function;
914
be.extern_function = extern_function;
915
fe.function_pointer = function_pointer;
916
be.function_pointer = function_pointer;
917
insns[from].successors.push_back(fe);
918
insns[to].predecessors.push_back(be);
919
}
920
921
static void pass3(void) {
922
// Build graph
923
for (size_t i = 0; i < insns.size(); i++) {
924
uint32_t addr = text_vaddr + i * 4;
925
Insn& insn = insns[i];
926
if (insn.no_following_successor) {
927
continue;
928
}
929
switch (insn.id) {
930
case MIPS_INS_BEQ:
931
case MIPS_INS_BGEZ:
932
case MIPS_INS_BGTZ:
933
case MIPS_INS_BLEZ:
934
case MIPS_INS_BLTZ:
935
case MIPS_INS_BNE:
936
case MIPS_INS_BEQZ:
937
case MIPS_INS_BNEZ:
938
case MIPS_INS_BC1F:
939
case MIPS_INS_BC1T:
940
add_edge(i, i + 1);
941
add_edge(i + 1, addr_to_i((uint32_t)insn.operands[insn.op_count - 1].imm));
942
break;
943
944
case MIPS_INS_BEQL:
945
case MIPS_INS_BGEZL:
946
case MIPS_INS_BGTZL:
947
case MIPS_INS_BLEZL:
948
case MIPS_INS_BLTZL:
949
case MIPS_INS_BNEL:
950
case MIPS_INS_BC1FL:
951
case MIPS_INS_BC1TL:
952
add_edge(i, i + 1);
953
add_edge(i, i + 2);
954
add_edge(i + 1, addr_to_i((uint32_t)insn.operands[insn.op_count - 1].imm));
955
insns[i + 1].no_following_successor = true; // don't inspect delay slot
956
break;
957
958
case MIPS_INS_B:
959
case MIPS_INS_J:
960
add_edge(i, i + 1);
961
add_edge(i + 1, addr_to_i((uint32_t)insn.operands[0].imm));
962
insns[i + 1].no_following_successor = true; // don't inspect delay slot
963
break;
964
965
case MIPS_INS_JR: {
966
add_edge(i, i + 1);
967
if (insn.jtbl_addr != 0) {
968
uint32_t jtbl_pos = insn.jtbl_addr - rodata_vaddr;
969
assert(jtbl_pos < rodata_section_len && jtbl_pos + insn.num_cases * 4 <= rodata_section_len);
970
for (uint32_t j = 0; j < insn.num_cases; j++) {
971
uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + j * 4) + gp_value;
972
add_edge(i + 1, addr_to_i(dest_addr));
973
}
974
} else {
975
assert(insn.operands[0].reg == MIPS_REG_RA && "jump to address in register not supported");
976
}
977
insns[i + 1].no_following_successor = true; // don't inspect delay slot
978
break;
979
}
980
981
case MIPS_INS_JAL: {
982
add_edge(i, i + 1);
983
uint32_t dest = (uint32_t)insn.operands[0].imm;
984
if (dest > mcount_addr && dest >= text_vaddr && dest < text_vaddr + text_section_len) {
985
add_edge(i + 1, addr_to_i(dest), true);
986
auto it = functions.find(dest);
987
assert(it != functions.end());
988
for (uint32_t ret_instr : it->second.returns) {
989
add_edge(addr_to_i(ret_instr), i + 2, false, true);
990
}
991
} else {
992
add_edge(i + 1, i + 2, false, false, true);
993
}
994
insns[i + 1].no_following_successor = true; // don't inspect delay slot
995
break;
996
}
997
998
case MIPS_INS_JALR:
999
// function pointer
1000
add_edge(i, i + 1);
1001
add_edge(i + 1, i + 2, false, false, false, true);
1002
insns[i + 1].no_following_successor = true; // don't inspect delay slot
1003
break;
1004
1005
default:
1006
add_edge(i, i + 1);
1007
break;
1008
}
1009
}
1010
}
1011
1012
static uint64_t map_reg(int32_t reg) {
1013
if (reg > MIPS_REG_31) {
1014
if (reg == MIPS_REG_HI) {
1015
reg = MIPS_REG_31 + 1;
1016
} else if (reg == MIPS_REG_LO) {
1017
reg = MIPS_REG_31 + 2;
1018
} else {
1019
return 0;
1020
}
1021
}
1022
return (uint64_t)1 << (reg - MIPS_REG_0 + 1);
1023
}
1024
1025
static uint64_t temporary_regs(void) {
1026
return
1027
map_reg(MIPS_REG_T0) |
1028
map_reg(MIPS_REG_T1) |
1029
map_reg(MIPS_REG_T2) |
1030
map_reg(MIPS_REG_T3) |
1031
map_reg(MIPS_REG_T4) |
1032
map_reg(MIPS_REG_T5) |
1033
map_reg(MIPS_REG_T6) |
1034
map_reg(MIPS_REG_T7) |
1035
map_reg(MIPS_REG_T8) |
1036
map_reg(MIPS_REG_T9);
1037
}
1038
1039
typedef enum {
1040
TYPE_NOP,
1041
TYPE_1S,
1042
TYPE_2S,
1043
TYPE_1D,
1044
TYPE_1D_1S,
1045
TYPE_1D_2S,
1046
TYPE_D_LO_HI_2S,
1047
TYPE_1S_POS1
1048
} TYPE;
1049
static TYPE insn_to_type(Insn& i) {
1050
switch (i.id) {
1051
case MIPS_INS_ADD:
1052
case MIPS_INS_ADDU:
1053
if (i.mnemonic != "add.s" && i.mnemonic != "add.d") {
1054
return TYPE_1D_2S;
1055
} else {
1056
return TYPE_NOP;
1057
}
1058
1059
case MIPS_INS_ADDI:
1060
case MIPS_INS_ADDIU:
1061
case MIPS_INS_ANDI:
1062
case MIPS_INS_ORI:
1063
case MIPS_INS_LB:
1064
case MIPS_INS_LBU:
1065
case MIPS_INS_LH:
1066
case MIPS_INS_LHU:
1067
case MIPS_INS_LW:
1068
case MIPS_INS_LWL:
1069
//case MIPS_INS_LWR:
1070
case MIPS_INS_MOVE:
1071
case MIPS_INS_NEGU:
1072
case MIPS_INS_NOT:
1073
case MIPS_INS_SLL:
1074
case MIPS_INS_SLTI:
1075
case MIPS_INS_SLTIU:
1076
case MIPS_INS_SRA:
1077
case MIPS_INS_SRL:
1078
case MIPS_INS_XORI:
1079
return TYPE_1D_1S;
1080
1081
case MIPS_INS_MFHI:
1082
i.operands[1].reg = MIPS_REG_HI;
1083
return TYPE_1D_1S;
1084
1085
case MIPS_INS_MFLO:
1086
i.operands[1].reg = MIPS_REG_LO;
1087
return TYPE_1D_1S;
1088
1089
case MIPS_INS_AND:
1090
case MIPS_INS_OR:
1091
case MIPS_INS_NOR:
1092
case MIPS_INS_SLLV:
1093
case MIPS_INS_SLT:
1094
case MIPS_INS_SLTU:
1095
case MIPS_INS_SRAV:
1096
case MIPS_INS_SRLV:
1097
case MIPS_INS_SUBU:
1098
case MIPS_INS_XOR:
1099
return TYPE_1D_2S;
1100
1101
case MIPS_INS_CFC1:
1102
case MIPS_INS_MFC1:
1103
case MIPS_INS_LI:
1104
case MIPS_INS_LUI:
1105
return TYPE_1D;
1106
1107
case MIPS_INS_CTC1:
1108
case MIPS_INS_BGEZ:
1109
case MIPS_INS_BGEZL:
1110
case MIPS_INS_BGTZ:
1111
case MIPS_INS_BGTZL:
1112
case MIPS_INS_BLEZ:
1113
case MIPS_INS_BLEZL:
1114
case MIPS_INS_BLTZ:
1115
case MIPS_INS_BLTZL:
1116
case MIPS_INS_BEQZ:
1117
case MIPS_INS_BNEZ:
1118
case MIPS_INS_MTC1:
1119
return TYPE_1S;
1120
1121
case MIPS_INS_BEQ:
1122
case MIPS_INS_BEQL:
1123
case MIPS_INS_BNE:
1124
case MIPS_INS_BNEL:
1125
case MIPS_INS_SB:
1126
case MIPS_INS_SH:
1127
case MIPS_INS_SW:
1128
case MIPS_INS_SWL:
1129
//case MIPS_INS_SWR:
1130
case MIPS_INS_TNE:
1131
case MIPS_INS_TEQ:
1132
case MIPS_INS_TGE:
1133
case MIPS_INS_TGEU:
1134
case MIPS_INS_TLT:
1135
return TYPE_2S;
1136
1137
case MIPS_INS_DIV:
1138
if (i.mnemonic != "div.s" && i.mnemonic != "div.d") {
1139
return TYPE_D_LO_HI_2S;
1140
} else {
1141
return TYPE_NOP;
1142
}
1143
1144
case MIPS_INS_DIVU:
1145
case MIPS_INS_MULT:
1146
case MIPS_INS_MULTU:
1147
return TYPE_D_LO_HI_2S;
1148
1149
case MIPS_INS_NEG:
1150
if (i.mnemonic != "neg.s" && i.mnemonic != "neg.d") {
1151
return TYPE_1D_1S;
1152
} else {
1153
return TYPE_NOP;
1154
}
1155
1156
case MIPS_INS_JALR:
1157
return TYPE_1S;
1158
1159
case MIPS_INS_JR:
1160
if (i.jtbl_addr != 0) {
1161
i.operands[0].reg = i.index_reg;
1162
}
1163
if (i.operands[0].reg == MIPS_REG_RA) {
1164
return TYPE_NOP;
1165
}
1166
return TYPE_1S;
1167
1168
case MIPS_INS_LWC1:
1169
case MIPS_INS_LDC1:
1170
case MIPS_INS_SWC1:
1171
case MIPS_INS_SDC1:
1172
return TYPE_1S_POS1;
1173
1174
default:
1175
return TYPE_NOP;
1176
}
1177
}
1178
1179
static void pass4(void) {
1180
vector<uint32_t> q;
1181
uint64_t livein_func_start = 1U | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | map_reg(MIPS_REG_SP) | map_reg(MIPS_REG_ZERO);
1182
1183
q.push_back(main_addr);
1184
insns[addr_to_i(main_addr)].f_livein = livein_func_start;
1185
1186
for (auto& it : data_function_pointers) {
1187
q.push_back(it.second);
1188
insns[addr_to_i(it.second)].f_livein = livein_func_start | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3);
1189
}
1190
for (auto& addr : li_function_pointers) {
1191
q.push_back(addr);
1192
insns[addr_to_i(addr)].f_livein = livein_func_start | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3);
1193
}
1194
1195
while (!q.empty()) {
1196
uint32_t addr = q.back();
1197
q.pop_back();
1198
uint32_t idx = addr_to_i(addr);
1199
Insn& i = insns[idx];
1200
uint64_t live = i.f_livein | 1;
1201
switch (insn_to_type(i)) {
1202
case TYPE_1D:
1203
live |= map_reg(i.operands[0].reg);
1204
break;
1205
1206
case TYPE_1D_1S:
1207
if (live & map_reg(i.operands[1].reg)) {
1208
live |= map_reg(i.operands[0].reg);
1209
}
1210
break;
1211
1212
case TYPE_1D_2S:
1213
if ((live & map_reg(i.operands[1].reg)) && (live & map_reg(i.operands[2].reg))) {
1214
live |= map_reg(i.operands[0].reg);
1215
}
1216
break;
1217
1218
case TYPE_D_LO_HI_2S:
1219
if ((live & map_reg(i.operands[0].reg)) && (live & map_reg(i.operands[1].reg))) {
1220
live |= map_reg(MIPS_REG_LO);
1221
live |= map_reg(MIPS_REG_HI);
1222
}
1223
break;
1224
}
1225
if ((i.f_liveout | live) == i.f_liveout) {
1226
// No new bits
1227
continue;
1228
}
1229
live |= i.f_liveout;
1230
i.f_liveout = live;
1231
1232
bool function_entry = false;
1233
for (Edge& e : i.successors) {
1234
uint64_t new_live = live;
1235
if (e.function_exit) {
1236
new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1) | map_reg(MIPS_REG_ZERO);
1237
} else if (e.function_entry) {
1238
new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1239
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_SP) | map_reg(MIPS_REG_ZERO);
1240
function_entry = true;
1241
} else if (e.extern_function) {
1242
string name;
1243
bool is_extern_function = false;
1244
size_t extern_function_id;
1245
auto it = symbol_names.find(insns[idx - 1].operands[0].imm);
1246
if (it != symbol_names.end()) {
1247
name = it->second;
1248
for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) {
1249
if (name == extern_functions[i].name) {
1250
is_extern_function = true;
1251
extern_function_id = i;
1252
break;
1253
}
1254
}
1255
if (!is_extern_function) {
1256
fprintf(stderr, "missing extern function: %s\n", name.c_str());
1257
}
1258
}
1259
assert(is_extern_function);
1260
auto& fn = extern_functions[extern_function_id];
1261
char ret_type = fn.params[0];
1262
new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1263
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1264
switch (ret_type) {
1265
case 'i':
1266
case 'u':
1267
case 'p':
1268
new_live |= map_reg(MIPS_REG_V0);
1269
break;
1270
case 'f':
1271
break;
1272
case 'd':
1273
break;
1274
case 'v':
1275
break;
1276
case 'l':
1277
case 'j':
1278
new_live |= map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1);
1279
break;
1280
}
1281
} else if (e.function_pointer) {
1282
new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1283
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1284
new_live |= map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1);
1285
}
1286
if ((insns[e.i].f_livein | new_live) != insns[e.i].f_livein) {
1287
insns[e.i].f_livein |= new_live;
1288
q.push_back(text_vaddr + e.i * 4);
1289
}
1290
}
1291
if (function_entry) {
1292
// add one edge that skips the function call, for callee-saved register liveness propagation
1293
live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1294
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1295
if ((insns[idx + 1].f_livein | live) != insns[idx + 1].f_livein) {
1296
insns[idx + 1].f_livein |= live;
1297
q.push_back(text_vaddr + (idx + 1) * 4);
1298
}
1299
}
1300
}
1301
}
1302
1303
static void pass5(void) {
1304
vector<uint32_t> q;
1305
1306
assert(functions.count(main_addr));
1307
1308
q = functions[main_addr].returns;
1309
for (auto addr : q) {
1310
insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0);
1311
}
1312
for (auto& it : data_function_pointers) {
1313
for (auto addr : functions[it.second].returns) {
1314
q.push_back(addr);
1315
insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1);
1316
}
1317
}
1318
for (auto& func_addr : li_function_pointers) {
1319
for (auto addr : functions[func_addr].returns) {
1320
q.push_back(addr);
1321
insns[addr_to_i(addr)].b_liveout = 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1);
1322
}
1323
}
1324
for (size_t i = 0; i < insns.size(); i++) {
1325
if (insns[i].f_livein != 0) {
1326
// Instruction is reachable
1327
q.push_back(text_vaddr + i * 4);
1328
}
1329
}
1330
1331
while (!q.empty()) {
1332
uint32_t addr = q.back();
1333
q.pop_back();
1334
uint32_t idx = addr_to_i(addr);
1335
Insn& i = insns[idx];
1336
uint64_t live = i.b_liveout | 1;
1337
switch (insn_to_type(i)) {
1338
case TYPE_1S:
1339
live |= map_reg(i.operands[0].reg);
1340
break;
1341
1342
case TYPE_1S_POS1:
1343
live |= map_reg(i.operands[1].reg);
1344
break;
1345
1346
case TYPE_2S:
1347
live |= map_reg(i.operands[0].reg);
1348
live |= map_reg(i.operands[1].reg);
1349
break;
1350
1351
case TYPE_1D:
1352
live &= ~map_reg(i.operands[0].reg);
1353
break;
1354
1355
case TYPE_1D_1S:
1356
if (live & map_reg(i.operands[0].reg)) {
1357
live &= ~map_reg(i.operands[0].reg);
1358
live |= map_reg(i.operands[1].reg);
1359
}
1360
break;
1361
1362
case TYPE_1D_2S:
1363
if (live & map_reg(i.operands[0].reg)) {
1364
live &= ~map_reg(i.operands[0].reg);
1365
live |= map_reg(i.operands[1].reg);
1366
live |= map_reg(i.operands[2].reg);
1367
}
1368
break;
1369
1370
case TYPE_D_LO_HI_2S: {
1371
bool used = (live & map_reg(MIPS_REG_LO)) || (live & map_reg(MIPS_REG_HI));
1372
live &= ~map_reg(MIPS_REG_LO);
1373
live &= ~map_reg(MIPS_REG_HI);
1374
if (used) {
1375
live |= map_reg(i.operands[0].reg);
1376
live |= map_reg(i.operands[1].reg);
1377
}
1378
break;
1379
}
1380
}
1381
if ((i.b_livein | live) == i.b_livein) {
1382
// No new bits
1383
continue;
1384
}
1385
live |= i.b_livein;
1386
i.b_livein = live;
1387
1388
bool function_exit = false;
1389
for (Edge& e : i.predecessors) {
1390
uint64_t new_live = live;
1391
if (e.function_exit) {
1392
new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_V1);
1393
function_exit = true;
1394
} else if (e.function_entry) {
1395
new_live &= 1U | map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1396
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_SP);
1397
} else if (e.extern_function) {
1398
string name;
1399
bool is_extern_function = false;
1400
size_t extern_function_id;
1401
auto it = symbol_names.find(insns[idx - 2].operands[0].imm);
1402
if (it != symbol_names.end()) {
1403
name = it->second;
1404
for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) {
1405
if (name == extern_functions[i].name) {
1406
is_extern_function = true;
1407
extern_function_id = i;
1408
break;
1409
}
1410
}
1411
}
1412
assert(is_extern_function);
1413
auto& fn = extern_functions[extern_function_id];
1414
uint64_t args = 1U;
1415
if (fn.flags & FLAG_VARARG) {
1416
// Assume the worst, that all four registers are used
1417
for (int j = 0; j < 4; j++) {
1418
args |= map_reg(MIPS_REG_A0 + j);
1419
}
1420
}
1421
int pos = 0;
1422
int pos_float = 0;
1423
bool only_floats_so_far = true;
1424
for (const char *p = fn.params + 1; *p != '\0'; ++p) {
1425
switch (*p) {
1426
case 'i':
1427
case 'u':
1428
case 'p':
1429
case 't':
1430
only_floats_so_far = false;
1431
if (pos < 4) {
1432
args |= map_reg(MIPS_REG_A0 + pos);
1433
}
1434
++pos;
1435
break;
1436
case 'f':
1437
if (only_floats_so_far && pos_float < 4) {
1438
pos_float += 2;
1439
} else if (pos < 4) {
1440
args |= map_reg(MIPS_REG_A0 + pos);
1441
}
1442
++pos;
1443
break;
1444
case 'd':
1445
if (pos % 1 != 0) {
1446
++pos;
1447
}
1448
if (only_floats_so_far && pos_float < 4) {
1449
pos_float += 2;
1450
} else if (pos < 4) {
1451
args |= map_reg(MIPS_REG_A0 + pos) | map_reg(MIPS_REG_A0 + pos + 1);
1452
}
1453
pos += 2;
1454
break;
1455
case 'l':
1456
case 'j':
1457
if (pos % 1 != 0) {
1458
++pos;
1459
}
1460
only_floats_so_far = false;
1461
if (pos < 4) {
1462
args |= map_reg(MIPS_REG_A0 + pos) | map_reg(MIPS_REG_A0 + pos + 1);
1463
}
1464
pos += 2;
1465
break;
1466
}
1467
}
1468
args |= map_reg(MIPS_REG_SP);
1469
new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1470
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1471
new_live |= args;
1472
} else if (e.function_pointer) {
1473
new_live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1474
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1475
new_live |= map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) | map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3);
1476
}
1477
if ((insns[e.i].b_liveout | new_live) != insns[e.i].b_liveout) {
1478
insns[e.i].b_liveout |= new_live;
1479
q.push_back(text_vaddr + e.i * 4);
1480
}
1481
}
1482
if (function_exit) {
1483
// add one edge that skips the function call, for callee-saved register liveness propagation
1484
live &= ~(map_reg(MIPS_REG_V0) | map_reg(MIPS_REG_A0) | map_reg(MIPS_REG_A1) |
1485
map_reg(MIPS_REG_A2) | map_reg(MIPS_REG_A3) | map_reg(MIPS_REG_V1) | temporary_regs());
1486
if ((insns[idx - 1].b_liveout | live) != insns[idx - 1].b_liveout) {
1487
insns[idx - 1].b_liveout |= live;
1488
q.push_back(text_vaddr + (idx - 1) * 4);
1489
}
1490
}
1491
}
1492
}
1493
1494
static void pass6(void) {
1495
for (auto& it : functions) {
1496
uint32_t addr = it.first;
1497
Function& f = it.second;
1498
for (uint32_t ret : f.returns) {
1499
Insn& i = insns[addr_to_i(ret)];
1500
if (i.f_liveout & i.b_liveout & map_reg(MIPS_REG_V1)) {
1501
f.nret = 2;
1502
} else if ((i.f_liveout & i.b_liveout & map_reg(MIPS_REG_V0)) && f.nret == 0) {
1503
f.nret = 1;
1504
}
1505
}
1506
Insn& insn = insns.at(addr_to_i(addr));
1507
for (int i = 0; i < 4; i++) {
1508
if (insn.f_livein & insn.b_livein & map_reg(MIPS_REG_A0 + i)) {
1509
f.nargs = 1 + i;
1510
}
1511
}
1512
f.v0_in = (insn.f_livein & insn.b_livein & map_reg(MIPS_REG_V0)) != 0 && !f.referenced_by_function_pointer;
1513
}
1514
}
1515
1516
static void dump(void) {
1517
for (size_t i = 0; i < insns.size(); i++) {
1518
Insn& insn = insns[i];
1519
uint32_t vaddr = text_vaddr + i * 4;
1520
if (label_addresses.count(vaddr)) {
1521
if (symbol_names.count(vaddr)) {
1522
printf("L%08x: //%s\n", vaddr, symbol_names[vaddr].c_str());
1523
} else {
1524
printf("L%08x:\n", vaddr);
1525
}
1526
}
1527
printf("\t%s %s\n", insn.mnemonic.c_str(), insn.op_str.c_str());
1528
}
1529
}
1530
1531
static const char *r(uint32_t reg) {
1532
return cs_reg_name(handle, reg);
1533
}
1534
1535
static const char *wr(uint32_t reg) {
1536
static const char *regs[] = {
1537
"f0.w[0]", "f0.w[1]",
1538
"f2.w[0]", "f2.w[1]",
1539
"f4.w[0]", "f4.w[1]",
1540
"f6.w[0]", "f6.w[1]",
1541
"f8.w[0]", "f8.w[1]",
1542
"f10.w[0]", "f10.w[1]",
1543
"f12.w[0]", "f12.w[1]",
1544
"f14.w[0]", "f14.w[1]",
1545
"f16.w[0]", "f16.w[1]",
1546
"f18.w[0]", "f18.w[1]",
1547
"f20.w[0]", "f20.w[1]",
1548
"f22.w[0]", "f22.w[1]",
1549
"f24.w[0]", "f24.w[1]",
1550
"f26.w[0]", "f26.w[1]",
1551
"f28.w[0]", "f28.w[1]",
1552
"f30.w[0]", "f30.w[1]"
1553
};
1554
assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31);
1555
return regs[reg - MIPS_REG_F0];
1556
}
1557
1558
static const char *fr(uint32_t reg) {
1559
static const char *regs[] = {
1560
"f0.f[0]", "f0.f[1]",
1561
"f2.f[0]", "f2.f[1]",
1562
"f4.f[0]", "f4.f[1]",
1563
"f6.f[0]", "f6.f[1]",
1564
"f8.f[0]", "f8.f[1]",
1565
"f10.f[0]", "f10.f[1]",
1566
"f12.f[0]", "f12.f[1]",
1567
"f14.f[0]", "f14.f[1]",
1568
"f16.f[0]", "f16.f[1]",
1569
"f18.f[0]", "f18.f[1]",
1570
"f20.f[0]", "f20.f[1]",
1571
"f22.f[0]", "f22.f[1]",
1572
"f24.f[0]", "f24.f[1]",
1573
"f26.f[0]", "f26.f[1]",
1574
"f28.f[0]", "f28.f[1]",
1575
"f30.f[0]", "f30.f[1]"
1576
};
1577
assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31);
1578
return regs[reg - MIPS_REG_F0];
1579
}
1580
1581
static const char *dr(uint32_t reg) {
1582
static const char *regs[] = {
1583
"f0.d",
1584
"f2.d",
1585
"f4.d",
1586
"f6.d",
1587
"f8.d",
1588
"f10.d",
1589
"f12.d",
1590
"f14.d",
1591
"f16.d",
1592
"f18.d",
1593
"f20.d",
1594
"f22.d",
1595
"f24.d",
1596
"f26.d",
1597
"f28.d",
1598
"f30.d"
1599
};
1600
assert(reg >= MIPS_REG_F0 && reg <= MIPS_REG_F31 && (reg - MIPS_REG_F0) % 2 == 0);
1601
return regs[(reg - MIPS_REG_F0) / 2];
1602
}
1603
1604
static void dump_instr(int i);
1605
1606
static void dump_cond_branch(int i, const char *lhs, const char *op, const char *rhs) {
1607
Insn& insn = insns[i];
1608
const char *cast1 = "";
1609
const char *cast2 = "";
1610
if (strcmp(op, "==") && strcmp(op, "!=")) {
1611
cast1 = "(int)";
1612
if (strcmp(rhs, "0")) {
1613
cast2 = "(int)";
1614
}
1615
}
1616
printf("if (%s%s %s %s%s) {", cast1, lhs, op, cast2, rhs);
1617
dump_instr(i + 1);
1618
printf("goto L%x;}\n", (uint32_t)insn.operands[insn.op_count - 1].imm);
1619
}
1620
1621
static void dump_cond_branch_likely(int i, const char *lhs, const char *op, const char *rhs) {
1622
uint32_t target = text_vaddr + (i + 2) * 4;
1623
dump_cond_branch(i, lhs, op, rhs);
1624
if (!TRACE) {
1625
printf("else goto L%x;\n", target);
1626
} else {
1627
printf("else {printf(\"pc=0x%08x (ignored)\\n\"); goto L%x;}\n", text_vaddr + (i + 1) * 4, target);
1628
}
1629
label_addresses.insert(target);
1630
}
1631
1632
static void dump_instr(int i) {
1633
const char *symbol_name = NULL;
1634
if (symbol_names.count(text_vaddr + i * 4) != 0) {
1635
symbol_name = symbol_names[text_vaddr + i * 4].c_str();
1636
printf("//%s:\n", symbol_name);
1637
}
1638
if (TRACE) {
1639
printf("++cnt; printf(\"pc=0x%08x%s%s\\n\"); ", text_vaddr + i * 4, symbol_name ? " " : "", symbol_name ? symbol_name : "");
1640
}
1641
Insn& insn = insns[i];
1642
if (!insn.is_jump && !conservative) {
1643
switch (insn_to_type(insn)) {
1644
case TYPE_1S:
1645
if (!(insn.f_livein & map_reg(insn.operands[0].reg))) {
1646
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1647
}
1648
break;
1649
case TYPE_1S_POS1:
1650
if (!(insn.f_livein & map_reg(insn.operands[1].reg))) {
1651
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1652
}
1653
break;
1654
case TYPE_2S:
1655
if (!(insn.f_livein & map_reg(insn.operands[0].reg)) || !(insn.f_livein & map_reg(insn.operands[1].reg))) {
1656
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1657
}
1658
break;
1659
case TYPE_1D_2S:
1660
if (!(insn.f_livein & map_reg(insn.operands[2].reg))) {
1661
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1662
break;
1663
}
1664
// fallthrough
1665
case TYPE_1D_1S:
1666
if (!(insn.f_livein & map_reg(insn.operands[1].reg))) {
1667
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1668
break;
1669
}
1670
// fallthrough
1671
case TYPE_1D:
1672
if (!(insn.b_liveout & map_reg(insn.operands[0].reg))) {
1673
printf("// bdead %llx ", (unsigned long long)insn.b_liveout);
1674
}
1675
break;
1676
case TYPE_D_LO_HI_2S:
1677
if (!(insn.f_livein & map_reg(insn.operands[0].reg)) || !(insn.f_livein & map_reg(insn.operands[1].reg))) {
1678
printf("// fdead %llx ", (unsigned long long)insn.f_livein);
1679
break;
1680
}
1681
if (!(insn.b_liveout & (map_reg(MIPS_REG_LO) | map_reg(MIPS_REG_HI)))) {
1682
printf("// bdead %llx ", (unsigned long long)insn.b_liveout);
1683
}
1684
break;
1685
}
1686
}
1687
switch (insn.id) {
1688
case MIPS_INS_ADD:
1689
case MIPS_INS_ADDU:
1690
if (insn.mnemonic == "add.s") {
1691
printf("%s = %s + %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg));
1692
} else if (insn.mnemonic == "add.d") {
1693
printf("%s = %s + %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg));
1694
} else {
1695
printf("%s = %s + %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
1696
}
1697
break;
1698
case MIPS_INS_ADDI:
1699
case MIPS_INS_ADDIU:
1700
printf("%s = %s + 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
1701
break;
1702
case MIPS_INS_AND:
1703
printf("%s = %s & %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
1704
break;
1705
case MIPS_INS_ANDI:
1706
printf("%s = %s & 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
1707
break;
1708
case MIPS_INS_BEQ:
1709
dump_cond_branch(i, r(insn.operands[0].reg), "==", r(insn.operands[1].reg));
1710
break;
1711
case MIPS_INS_BEQL:
1712
dump_cond_branch_likely(i, r(insn.operands[0].reg), "==", r(insn.operands[1].reg));
1713
break;
1714
case MIPS_INS_BGEZ:
1715
dump_cond_branch(i, r(insn.operands[0].reg), ">=", "0");
1716
break;
1717
case MIPS_INS_BGEZL:
1718
dump_cond_branch_likely(i, r(insn.operands[0].reg), ">=", "0");
1719
break;
1720
case MIPS_INS_BGTZ:
1721
dump_cond_branch(i, r(insn.operands[0].reg), ">", "0");
1722
break;
1723
case MIPS_INS_BGTZL:
1724
dump_cond_branch_likely(i, r(insn.operands[0].reg), ">", "0");
1725
break;
1726
case MIPS_INS_BLEZ:
1727
dump_cond_branch(i, r(insn.operands[0].reg), "<=", "0");
1728
break;
1729
case MIPS_INS_BLEZL:
1730
dump_cond_branch_likely(i, r(insn.operands[0].reg), "<=", "0");
1731
break;
1732
case MIPS_INS_BLTZ:
1733
dump_cond_branch(i, r(insn.operands[0].reg), "<", "0");
1734
break;
1735
case MIPS_INS_BLTZL:
1736
dump_cond_branch_likely(i, r(insn.operands[0].reg), "<", "0");
1737
break;
1738
case MIPS_INS_BNE:
1739
dump_cond_branch(i, r(insn.operands[0].reg), "!=", r(insn.operands[1].reg));
1740
break;
1741
case MIPS_INS_BNEL:
1742
dump_cond_branch_likely(i, r(insn.operands[0].reg), "!=", insn.mnemonic == "bnezl" ? "0" : r(insn.operands[1].reg));
1743
break;
1744
case MIPS_INS_BREAK:
1745
printf("abort();\n");
1746
break;
1747
case MIPS_INS_BEQZ:
1748
dump_cond_branch(i, r(insn.operands[0].reg), "==", "0");
1749
break;
1750
/*case MIPS_INS_BEQZL:
1751
dump_cond_branch_likely(i, r(insn.operands[0].reg), "==", "0");
1752
break;*/
1753
case MIPS_INS_B:
1754
dump_instr(i + 1);
1755
printf("goto L%x;\n", (int32_t)insn.operands[0].imm);
1756
break;
1757
case MIPS_INS_BC1F:
1758
case MIPS_INS_BC1T:
1759
printf("if (%scf) {", insn.id == MIPS_INS_BC1F ? "!" : "");
1760
dump_instr(i + 1);
1761
printf("goto L%x;}\n", (int32_t)insn.operands[0].imm);
1762
break;
1763
case MIPS_INS_BC1FL:
1764
case MIPS_INS_BC1TL:
1765
{
1766
uint32_t target = text_vaddr + (i + 2) * 4;
1767
printf("if (%scf) {", insn.id == MIPS_INS_BC1FL ? "!" : "");
1768
dump_instr(i + 1);
1769
printf("goto L%x;}\n", (int32_t)insn.operands[0].imm);
1770
if (!TRACE) {
1771
printf("else goto L%x;\n", target);
1772
} else {
1773
printf("else {printf(\"pc=0x%08x (ignored)\\n\"); goto L%x;}\n", text_vaddr + (i + 1) * 4, target);
1774
}
1775
label_addresses.insert(target);
1776
break;
1777
}
1778
case MIPS_INS_BNEZ:
1779
dump_cond_branch(i, r(insn.operands[0].reg), "!=", "0");
1780
break;
1781
/*case MIPS_INS_BNEZL:
1782
dump_cond_branch_likely(i, r(insn.operands[0].reg), "!=", "0");
1783
break;*/
1784
case MIPS_INS_C:
1785
if (insn.mnemonic == "c.lt.s") {
1786
printf("cf = %s < %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg));
1787
} else if (insn.mnemonic == "c.le.s") {
1788
printf("cf = %s <= %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg));
1789
} else if (insn.mnemonic == "c.eq.s") {
1790
printf("cf = %s == %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg));
1791
} else if (insn.mnemonic == "c.lt.d") {
1792
printf("cf = %s < %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg));
1793
} else if (insn.mnemonic == "c.le.d") {
1794
printf("cf = %s <= %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg));
1795
} else if (insn.mnemonic == "c.eq.d") {
1796
printf("cf = %s == %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg));
1797
}
1798
break;
1799
case MIPS_INS_CVT:
1800
if (insn.mnemonic == "cvt.s.w") {
1801
printf("%s = (int)%s;\n", fr(insn.operands[0].reg), wr(insn.operands[1].reg));
1802
} else if (insn.mnemonic == "cvt.d.w") {
1803
printf("%s = (int)%s;\n", dr(insn.operands[0].reg), wr(insn.operands[1].reg));
1804
} else if (insn.mnemonic == "cvt.d.s") {
1805
printf("%s = %s;\n", dr(insn.operands[0].reg), fr(insn.operands[1].reg));
1806
} else if (insn.mnemonic == "cvt.s.d") {
1807
printf("%s = %s;\n", fr(insn.operands[0].reg), dr(insn.operands[1].reg));
1808
} else if (insn.mnemonic == "cvt.w.d") {
1809
printf("%s = cvt_w_d(%s);\n", wr(insn.operands[0].reg), dr(insn.operands[1].reg));
1810
} else if (insn.mnemonic == "cvt.w.s") {
1811
printf("%s = cvt_w_s(%s);\n", wr(insn.operands[0].reg), fr(insn.operands[1].reg));
1812
} else {
1813
goto unimplemented;
1814
}
1815
break;
1816
case MIPS_INS_CFC1:
1817
assert(insn.operands[1].reg == MIPS_REG_31);
1818
printf("%s = fcsr;\n", r(insn.operands[0].reg));
1819
break;
1820
case MIPS_INS_CTC1:
1821
assert(insn.operands[1].reg == MIPS_REG_31);
1822
printf("fcsr = %s;\n", r(insn.operands[0].reg));
1823
break;
1824
case MIPS_INS_DIV:
1825
if (insn.mnemonic == "div.s") {
1826
assert(insn.op_count == 3);
1827
printf("%s = %s / %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg));
1828
} else if (insn.mnemonic == "div.d") {
1829
assert(insn.op_count == 3);
1830
printf("%s = %s / %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg));
1831
} else {
1832
assert(insn.op_count == 2);
1833
printf("lo = (int)%s / (int)%s; ", r(insn.operands[0].reg), r(insn.operands[1].reg));
1834
printf("hi = (int)%s %% (int)%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
1835
}
1836
break;
1837
case MIPS_INS_DIVU:
1838
assert(insn.op_count == 2);
1839
printf("lo = %s / %s; ", r(insn.operands[0].reg), r(insn.operands[1].reg));
1840
printf("hi = %s %% %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
1841
break;
1842
case MIPS_INS_MOV:
1843
if (insn.mnemonic == "mov.s") {
1844
printf("%s = %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg));
1845
} else if (insn.mnemonic == "mov.d") {
1846
printf("%s = %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg));
1847
} else {
1848
goto unimplemented;
1849
}
1850
break;
1851
case MIPS_INS_MUL:
1852
if (insn.mnemonic == "mul.s") {
1853
printf("%s = %s * %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg));
1854
} else if (insn.mnemonic == "mul.d") {
1855
printf("%s = %s * %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg));
1856
} else {
1857
goto unimplemented;
1858
}
1859
break;
1860
case MIPS_INS_NEG:
1861
if (insn.mnemonic == "neg.s") {
1862
printf("%s = -%s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg));
1863
} else if (insn.mnemonic == "neg.d") {
1864
printf("%s = -%s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg));
1865
} else {
1866
printf("%s = -%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
1867
}
1868
break;
1869
case MIPS_INS_SUB:
1870
if (insn.mnemonic == "sub.s") {
1871
printf("%s = %s - %s;\n", fr(insn.operands[0].reg), fr(insn.operands[1].reg), fr(insn.operands[2].reg));
1872
} else if (insn.mnemonic == "sub.d") {
1873
printf("%s = %s - %s;\n", dr(insn.operands[0].reg), dr(insn.operands[1].reg), dr(insn.operands[2].reg));
1874
} else {
1875
goto unimplemented;
1876
}
1877
break;
1878
case MIPS_INS_J:
1879
dump_instr(i + 1);
1880
printf("goto L%x;\n", (uint32_t)insn.operands[0].imm);
1881
break;
1882
case MIPS_INS_JAL:
1883
{
1884
string name;
1885
bool is_extern_function = false;
1886
size_t extern_function_id;
1887
auto it = symbol_names.find(insn.operands[0].imm);
1888
if (it != symbol_names.end()) {
1889
name = it->second;
1890
for (size_t i = 0; i < sizeof(extern_functions) / sizeof(extern_functions[0]); i++) {
1891
if (name == extern_functions[i].name) {
1892
is_extern_function = true;
1893
extern_function_id = i;
1894
break;
1895
}
1896
}
1897
}
1898
dump_instr(i + 1);
1899
if (is_extern_function) {
1900
auto& fn = extern_functions[extern_function_id];
1901
if (fn.flags & FLAG_VARARG) {
1902
for (int j = 0; j < 4; j++) {
1903
printf("MEM_U32(sp + %d) = %s;\n", j * 4, r(MIPS_REG_A0 + j));
1904
}
1905
}
1906
char ret_type = fn.params[0];
1907
if (ret_type != 'v') {
1908
switch (ret_type) {
1909
case 'i':
1910
case 'u':
1911
case 'p':
1912
printf("%s = ", r(MIPS_REG_V0));
1913
break;
1914
case 'f':
1915
printf("%s = ", fr(MIPS_REG_F0));
1916
break;
1917
case 'd':
1918
printf("%s = ", dr(MIPS_REG_F0));
1919
break;
1920
case 'l':
1921
case 'j':
1922
printf("temp64 = ");
1923
break;
1924
}
1925
}
1926
printf("wrapper_%s(", name.c_str());
1927
bool first = true;
1928
if (!(fn.flags & FLAG_NO_MEM)) {
1929
printf("mem");
1930
first = false;
1931
}
1932
int pos = 0;
1933
int pos_float = 0;
1934
bool only_floats_so_far = true;
1935
bool needs_sp = false;
1936
for (const char *p = fn.params + 1; *p != '\0'; ++p) {
1937
if (!first) {
1938
printf(", ");
1939
}
1940
first = false;
1941
switch (*p) {
1942
case 't':
1943
printf("trampoline, ");
1944
needs_sp = true;
1945
// fallthrough
1946
case 'i':
1947
case 'u':
1948
case 'p':
1949
only_floats_so_far = false;
1950
if (pos < 4) {
1951
printf("%s", r(MIPS_REG_A0 + pos));
1952
} else {
1953
printf("MEM_%c32(sp + %d)", *p == 'i' ? 'S' : 'U', pos * 4);
1954
}
1955
++pos;
1956
break;
1957
case 'f':
1958
if (only_floats_so_far && pos_float < 4) {
1959
printf("%s", fr(MIPS_REG_F12 + pos_float));
1960
pos_float += 2;
1961
} else if (pos < 4) {
1962
printf("BITCAST_U32_TO_F32(%s)", r(MIPS_REG_A0 + pos));
1963
} else {
1964
printf("BITCAST_U32_TO_F32(MEM_U32(sp + %d))", pos * 4);
1965
}
1966
++pos;
1967
break;
1968
case 'd':
1969
if (pos % 1 != 0) {
1970
++pos;
1971
}
1972
if (only_floats_so_far && pos_float < 4) {
1973
printf("%s", dr(MIPS_REG_F12 + pos_float));
1974
pos_float += 2;
1975
} else if (pos < 4) {
1976
printf("BITCAST_U64_TO_F64(((uint64_t)%s << 32) | (uint64_t)%s)", r(MIPS_REG_A0 + pos), r(MIPS_REG_A0 + pos + 1));
1977
} else {
1978
printf("BITCAST_U64_TO_F64(((uint64_t)MEM_U32(sp + %d) << 32) | (uint64_t)MEM_U32(sp + %d))", pos * 4, (pos + 1) * 4);
1979
}
1980
pos += 2;
1981
break;
1982
case 'l':
1983
case 'j':
1984
if (pos % 1 != 0) {
1985
++pos;
1986
}
1987
only_floats_so_far = false;
1988
if (*p == 'l') {
1989
printf("(int64_t)");
1990
}
1991
if (pos < 4) {
1992
printf("(((uint64_t)%s << 32) | (uint64_t)%s)", r(MIPS_REG_A0 + pos), r(MIPS_REG_A0 + pos + 1));
1993
} else {
1994
printf("(((uint64_t)MEM_U32(sp + %d) << 32) | (uint64_t)MEM_U32(sp + %d))", pos * 4, (pos + 1) * 4);
1995
}
1996
pos += 2;
1997
break;
1998
}
1999
}
2000
if ((fn.flags & FLAG_VARARG) || needs_sp) {
2001
printf("%s%s", first ? "" : ", ", r(MIPS_REG_SP));
2002
}
2003
printf(");\n");
2004
if (ret_type == 'l' || ret_type == 'j') {
2005
printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0));
2006
printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1));
2007
}
2008
if (!name.empty()) {
2009
//printf("printf(\"%s %%x\\n\", %s);\n", name.c_str(), r(MIPS_REG_A0));
2010
}
2011
} else {
2012
Function& f = functions.find((uint32_t)insn.operands[0].imm)->second;
2013
if (f.nret == 1) {
2014
printf("v0 = ");
2015
} else if (f.nret == 2) {
2016
printf("temp64 = ");
2017
}
2018
if (!name.empty()) {
2019
//printf("printf(\"%s %%x\\n\", %s);\n", name.c_str(), r(MIPS_REG_A0));
2020
printf("f_%s", name.c_str());
2021
} else {
2022
printf("func_%x", (uint32_t)insn.operands[0].imm);
2023
}
2024
printf("(mem, sp");
2025
if (f.v0_in) {
2026
printf(", %s", r(MIPS_REG_V0));
2027
}
2028
for (uint32_t i = 0; i < f.nargs; i++) {
2029
printf(", %s", r(MIPS_REG_A0 + i));
2030
}
2031
printf(");\n");
2032
if (f.nret == 2) {
2033
printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0));
2034
printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1));
2035
}
2036
}
2037
printf("goto L%x;\n", text_vaddr + (i + 2) * 4);
2038
label_addresses.insert(text_vaddr + (i + 2) * 4);
2039
break;
2040
}
2041
case MIPS_INS_JALR:
2042
printf("fp_dest = %s;\n", r(insn.operands[0].reg));
2043
dump_instr(i + 1);
2044
printf("temp64 = trampoline(mem, sp, %s, %s, %s, %s, fp_dest);\n",
2045
r(MIPS_REG_A0), r(MIPS_REG_A1), r(MIPS_REG_A2), r(MIPS_REG_A3));
2046
printf("%s = (uint32_t)(temp64 >> 32);\n", r(MIPS_REG_V0));
2047
printf("%s = (uint32_t)temp64;\n", r(MIPS_REG_V1));
2048
printf("goto L%x;\n", text_vaddr + (i + 2) * 4);
2049
label_addresses.insert(text_vaddr + (i + 2) * 4);
2050
break;
2051
case MIPS_INS_JR:
2052
if (insn.jtbl_addr != 0) {
2053
uint32_t jtbl_pos = insn.jtbl_addr - rodata_vaddr;
2054
assert(jtbl_pos < rodata_section_len && jtbl_pos + insn.num_cases * 4 <= rodata_section_len);
2055
#if 1
2056
printf(";static void *const Lswitch%x[] = {\n", insn.jtbl_addr);
2057
for (uint32_t i = 0; i < insn.num_cases; i++) {
2058
uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + i * 4) + gp_value;
2059
printf("&&L%x,\n", dest_addr);
2060
label_addresses.insert(dest_addr);
2061
}
2062
printf("};\n");
2063
printf("dest = Lswitch%x[%s];\n", insn.jtbl_addr, r(insn.index_reg));
2064
dump_instr(i + 1);
2065
printf("goto *dest;\n");
2066
#else
2067
assert(insns[i + 1].id == MIPS_INS_NOP);
2068
printf("switch (%s) {\n", r(insn.index_reg));
2069
for (uint32_t i = 0; i < insn.num_cases; i++) {
2070
uint32_t dest_addr = read_u32_be(rodata_section + jtbl_pos + i * 4) + gp_value;
2071
printf("case %u: goto L%x;\n", i, dest_addr);
2072
label_addresses.insert(dest_addr);
2073
}
2074
printf("}\n");
2075
#endif
2076
} else {
2077
if (insn.operands[0].reg != MIPS_REG_RA) {
2078
printf("UNSUPPORTED JR %s %s\n", insn.op_str.c_str(), r(insn.operands[0].reg));
2079
} else {
2080
dump_instr(i + 1);
2081
switch (find_function(text_vaddr + i * 4)->second.nret) {
2082
case 0:
2083
printf("return;\n");
2084
break;
2085
case 1:
2086
printf("return v0;\n");
2087
break;
2088
case 2:
2089
printf("return ((uint64_t)v0 << 32) | v1;\n");
2090
break;
2091
}
2092
}
2093
}
2094
break;
2095
case MIPS_INS_LB:
2096
printf("%s = MEM_S8(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2097
break;
2098
case MIPS_INS_LBU:
2099
printf("%s = MEM_U8(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2100
break;
2101
case MIPS_INS_LH:
2102
printf("%s = MEM_S16(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2103
break;
2104
case MIPS_INS_LHU:
2105
printf("%s = MEM_U16(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2106
break;
2107
case MIPS_INS_LUI:
2108
printf("%s = 0x%x;\n", r(insn.operands[0].reg), ((uint32_t)insn.operands[1].imm) << 16);
2109
break;
2110
case MIPS_INS_LW:
2111
printf("%s = MEM_U32(%s + %d);\n", r(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2112
break;
2113
case MIPS_INS_LWC1:
2114
printf("%s = MEM_U32(%s + %d);\n", wr(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2115
break;
2116
case MIPS_INS_LDC1:
2117
assert((insn.operands[0].reg - MIPS_REG_F0) % 2 == 0);
2118
printf("%s = MEM_U32(%s + %d);\n", wr(insn.operands[0].reg + 1), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2119
printf("%s = MEM_U32(%s + %d + 4);\n", wr(insn.operands[0].reg), r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2120
break;
2121
case MIPS_INS_LWL:
2122
{
2123
const char *reg = r(insn.operands[0].reg);
2124
printf("%s = %s + %d; ", reg, r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp);
2125
printf("%s = (MEM_U8(%s) << 24) | (MEM_U8(%s + 1) << 16) | (MEM_U8(%s + 2) << 8) | MEM_U8(%s + 3);\n", reg, reg, reg, reg, reg);
2126
break;
2127
}
2128
case MIPS_INS_LWR:
2129
printf("//lwr %s\n", insn.op_str.c_str());
2130
break;
2131
case MIPS_INS_LI:
2132
if (insn.is_global_got_memop && text_vaddr <= insn.operands[1].imm && insn.operands[1].imm < text_vaddr + text_section_len) {
2133
printf("%s = 0x%x; // function pointer\n", r(insn.operands[0].reg), (uint32_t)insn.operands[1].imm);
2134
label_addresses.insert((uint32_t)insn.operands[1].imm);
2135
} else {
2136
printf("%s = 0x%x;\n", r(insn.operands[0].reg), (uint32_t)insn.operands[1].imm);
2137
}
2138
break;
2139
case MIPS_INS_MFC1:
2140
printf("%s = %s;\n", r(insn.operands[0].reg), wr(insn.operands[1].reg));
2141
break;
2142
case MIPS_INS_MFHI:
2143
printf("%s = hi;\n", r(insn.operands[0].reg));
2144
break;
2145
case MIPS_INS_MFLO:
2146
printf("%s = lo;\n", r(insn.operands[0].reg));
2147
break;
2148
case MIPS_INS_MOVE:
2149
printf("%s = %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2150
break;
2151
case MIPS_INS_MTC1:
2152
printf("%s = %s;\n", wr(insn.operands[1].reg), r(insn.operands[0].reg));
2153
break;
2154
case MIPS_INS_MULT:
2155
printf("lo = %s * %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2156
printf("hi = (uint32_t)((int64_t)(int)%s * (int64_t)(int)%s >> 32);\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2157
break;
2158
case MIPS_INS_MULTU:
2159
printf("lo = %s * %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2160
printf("hi = (uint32_t)((uint64_t)%s * (uint64_t)%s >> 32);\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2161
break;
2162
case MIPS_INS_NEGU:
2163
printf("%s = -%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2164
break;
2165
case MIPS_INS_NOR:
2166
printf("%s = ~(%s | %s);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2167
break;
2168
case MIPS_INS_NOT:
2169
printf("%s = ~%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg));
2170
break;
2171
case MIPS_INS_OR:
2172
printf("%s = %s | %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2173
break;
2174
case MIPS_INS_ORI:
2175
printf("%s = %s | 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2176
break;
2177
case MIPS_INS_SB:
2178
printf("MEM_U8(%s + %d) = (uint8_t)%s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg));
2179
break;
2180
case MIPS_INS_SH:
2181
printf("MEM_U16(%s + %d) = (uint16_t)%s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg));
2182
break;
2183
case MIPS_INS_SLL:
2184
printf("%s = %s << %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2185
break;
2186
case MIPS_INS_SLLV:
2187
printf("%s = %s << (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2188
break;
2189
case MIPS_INS_SLT:
2190
printf("%s = (int)%s < (int)%s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2191
break;
2192
case MIPS_INS_SLTI:
2193
printf("%s = (int)%s < (int)0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2194
break;
2195
case MIPS_INS_SLTIU:
2196
printf("%s = %s < 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2197
break;
2198
case MIPS_INS_SLTU:
2199
printf("%s = %s < %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2200
break;
2201
case MIPS_INS_SRA:
2202
printf("%s = (int)%s >> %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2203
break;
2204
case MIPS_INS_SRAV:
2205
printf("%s = (int)%s >> (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2206
break;
2207
case MIPS_INS_SRL:
2208
printf("%s = %s >> %d;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2209
break;
2210
case MIPS_INS_SRLV:
2211
printf("%s = %s >> (%s & 0x1f);\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2212
break;
2213
case MIPS_INS_SUBU:
2214
printf("%s = %s - %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2215
break;
2216
case MIPS_INS_SW:
2217
printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, r(insn.operands[0].reg));
2218
break;
2219
case MIPS_INS_SWC1:
2220
printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg));
2221
break;
2222
case MIPS_INS_SDC1:
2223
assert((insn.operands[0].reg - MIPS_REG_F0) % 2 == 0);
2224
printf("MEM_U32(%s + %d) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg + 1));
2225
printf("MEM_U32(%s + %d + 4) = %s;\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, wr(insn.operands[0].reg));
2226
break;
2227
case MIPS_INS_SWL:
2228
for (int i = 0; i < 4; i++) {
2229
printf("MEM_U8(%s + %d + %d) = (uint8_t)(%s >> %d);\n", r(insn.operands[1].mem.base), (int)insn.operands[1].mem.disp, i, r(insn.operands[0].reg), (3 - i) * 8);
2230
}
2231
break;
2232
case MIPS_INS_SWR:
2233
printf("//swr %s\n", insn.op_str.c_str());
2234
break;
2235
case MIPS_INS_TRUNC:
2236
if (insn.mnemonic == "trunc.w.s") {
2237
printf("%s = (int)%s;\n", wr(insn.operands[0].reg), fr(insn.operands[1].reg));
2238
} else if (insn.mnemonic == "trunc.w.d") {
2239
printf("%s = (int)%s;\n", wr(insn.operands[0].reg), dr(insn.operands[1].reg));
2240
} else {
2241
goto unimplemented;
2242
}
2243
break;
2244
case MIPS_INS_XOR:
2245
printf("%s = %s ^ %s;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), r(insn.operands[2].reg));
2246
break;
2247
case MIPS_INS_XORI:
2248
printf("%s = %s ^ 0x%x;\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (uint32_t)insn.operands[2].imm);
2249
break;
2250
case MIPS_INS_TNE:
2251
printf("assert(%s == %s && \"tne %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm);
2252
break;
2253
case MIPS_INS_TEQ:
2254
printf("assert(%s != %s && \"teq %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm);
2255
break;
2256
case MIPS_INS_TGE:
2257
printf("assert((int)%s < (int)%s && \"tge %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm);
2258
break;
2259
case MIPS_INS_TGEU:
2260
printf("assert(%s < %s && \"tgeu %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm);
2261
break;
2262
case MIPS_INS_TLT:
2263
printf("assert((int)%s >= (int)%s && \"tlt %d\");\n", r(insn.operands[0].reg), r(insn.operands[1].reg), (int)insn.operands[2].imm);
2264
break;
2265
case MIPS_INS_NOP:
2266
printf("//nop;\n");
2267
break;
2268
default:
2269
unimplemented:
2270
printf("UNIMPLEMENTED %s %s\n", insn.mnemonic.c_str(), insn.op_str.c_str());
2271
break;
2272
}
2273
}
2274
2275
static void inspect_data_function_pointers(vector<pair<uint32_t, uint32_t>>& ret, const uint8_t *section, uint32_t section_vaddr, uint32_t len) {
2276
for (uint32_t i = 0; i < len; i += 4) {
2277
uint32_t addr = read_u32_be(section + i);
2278
if (addr == 0x430b00 || addr == 0x433b00) {
2279
// in as1, not function pointers (normal integers)
2280
continue;
2281
}
2282
if (addr == 0x4a0000) {
2283
// in copt
2284
continue;
2285
}
2286
if (section_vaddr + i >= procedure_table_start && section_vaddr + i < procedure_table_start + procedure_table_len) {
2287
// some linking table with a "all" functions, in as1 5.3
2288
continue;
2289
}
2290
if (addr >= text_vaddr && addr < text_vaddr + text_section_len && addr % 4 == 0) {
2291
#if INSPECT_FUNCTION_POINTERS
2292
fprintf(stderr, "assuming function pointer 0x%x at 0x%x\n", addr, section_vaddr + i);
2293
#endif
2294
ret.push_back(make_pair(section_vaddr + i, addr));
2295
label_addresses.insert(addr);
2296
functions[addr].referenced_by_function_pointer = true;
2297
}
2298
}
2299
}
2300
2301
static void dump_function_signature(Function& f, uint32_t vaddr) {
2302
printf("static ");
2303
switch (f.nret) {
2304
case 0:
2305
printf("void ");
2306
break;
2307
case 1:
2308
printf("uint32_t ");
2309
break;
2310
case 2:
2311
printf("uint64_t ");
2312
break;
2313
}
2314
auto name_it = symbol_names.find(vaddr);
2315
if (name_it != symbol_names.end()) {
2316
printf("f_%s", name_it->second.c_str());
2317
} else {
2318
printf("func_%x", vaddr);
2319
}
2320
printf("(uint8_t *mem, uint32_t sp");
2321
if (f.v0_in) {
2322
printf(", uint32_t %s", r(MIPS_REG_V0));
2323
}
2324
for (uint32_t i = 0; i < f.nargs; i++) {
2325
printf(", uint32_t %s", r(MIPS_REG_A0 + i));
2326
}
2327
printf(")");
2328
}
2329
2330
static void dump_c(void) {
2331
map<string, uint32_t> symbol_names_inv;
2332
for (auto& it : symbol_names) {
2333
symbol_names_inv[it.second] = it.first;
2334
}
2335
2336
uint32_t min_addr = ~0;
2337
uint32_t max_addr = 0;
2338
2339
if (data_section_len > 0) {
2340
min_addr = std::min(min_addr, data_vaddr);
2341
max_addr = std::max(max_addr, data_vaddr + data_section_len);
2342
}
2343
if (rodata_section_len > 0) {
2344
min_addr = std::min(min_addr, rodata_vaddr);
2345
max_addr = std::max(max_addr, rodata_vaddr + rodata_section_len);
2346
}
2347
if (bss_section_len) {
2348
min_addr = std::min(min_addr, bss_vaddr);
2349
max_addr = std::max(max_addr, bss_vaddr + bss_section_len);
2350
}
2351
2352
min_addr = min_addr & ~0xfff;
2353
max_addr = (max_addr + 0xfff) & ~0xfff;
2354
2355
uint32_t stack_bottom = min_addr;
2356
min_addr -= 1 * 1024 * 1024; // 1 MB stack
2357
stack_bottom -= 16; // for main's stack frame
2358
2359
printf("#include \"header.h\"\n");
2360
if (conservative) {
2361
printf("static uint32_t s0, s1, s2, s3, s4, s5, s6, s7, fp;\n");
2362
}
2363
printf("static const uint32_t rodata[] = {\n");
2364
for (size_t i = 0; i < rodata_section_len; i += 4) {
2365
printf("0x%x,%s", read_u32_be(rodata_section + i), i % 32 == 28 ? "\n" : "");
2366
}
2367
printf("};\n");
2368
printf("static const uint32_t data[] = {\n");
2369
for (size_t i = 0; i < data_section_len; i += 4) {
2370
printf("0x%x,%s", read_u32_be(data_section + i), i % 32 == 28 ? "\n" : "");
2371
}
2372
printf("};\n");
2373
2374
/*if (!data_function_pointers.empty()) {
2375
printf("static const struct { uint32_t orig_addr; void *recompiled_addr; } data_function_pointers[] = {\n");
2376
for (auto item : data_function_pointers) {
2377
printf("{0x%x, &&L%x},\n", item.first, item.second);
2378
}
2379
printf("};\n");
2380
}*/
2381
2382
if (TRACE) {
2383
printf("static unsigned long long int cnt = 0;\n");
2384
}
2385
2386
for (auto& f_it : functions) {
2387
if (insns[addr_to_i(f_it.first)].f_livein != 0) {
2388
// Function is used
2389
dump_function_signature(f_it.second, f_it.first);
2390
printf(";\n");
2391
}
2392
}
2393
2394
if (!data_function_pointers.empty() || !li_function_pointers.empty()) {
2395
printf("uint64_t trampoline(uint8_t *mem, uint32_t sp, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t fp_dest) {\n");
2396
printf("switch (fp_dest) {\n");
2397
for (auto& it : functions) {
2398
Function& f = it.second;
2399
if (f.referenced_by_function_pointer) {
2400
printf("case 0x%x: ", it.first);
2401
if (f.nret == 1) {
2402
printf("return (uint64_t)");
2403
} else if (f.nret == 2) {
2404
printf("return ");
2405
}
2406
auto name_it = symbol_names.find(it.first);
2407
if (name_it != symbol_names.end()) {
2408
printf("f_%s", name_it->second.c_str());
2409
} else {
2410
printf("func_%x", it.first);
2411
}
2412
printf("(mem, sp");
2413
for (int i = 0; i < f.nargs; i++) {
2414
printf(", a%d", i);
2415
}
2416
printf(")");
2417
if (f.nret == 1) {
2418
printf(" << 32");
2419
}
2420
printf(";");
2421
if (f.nret == 0) {
2422
printf(" return 0;");
2423
}
2424
printf("\n");
2425
}
2426
}
2427
printf("default: abort();");
2428
printf("}\n");
2429
printf("}\n");
2430
}
2431
2432
printf("int run(uint8_t *mem, int argc, char *argv[]) {\n");
2433
printf("mmap_initial_data_range(mem, 0x%x, 0x%x);\n", min_addr, max_addr);
2434
2435
printf("memcpy(mem + 0x%x, rodata, 0x%x);\n", rodata_vaddr, rodata_section_len);
2436
printf("memcpy(mem + 0x%x, data, 0x%x);\n", data_vaddr, data_section_len);
2437
2438
/*if (!data_function_pointers.empty()) {
2439
if (!LABELS_64_BIT) {
2440
printf("for (int i = 0; i < %d; i++) MEM_U32(data_function_pointers[i].orig_addr) = (uint32_t)(uintptr_t)data_function_pointers[i].recompiled_addr;\n", (int)data_function_pointers.size());
2441
} else {
2442
printf("for (int i = 0; i < %d; i++) MEM_U32(data_function_pointers[i].orig_addr) = (uint32_t)((uintptr_t)data_function_pointers[i].recompiled_addr - (uintptr_t)&&Loffset);\n", (int)data_function_pointers.size());
2443
}
2444
}*/
2445
2446
printf("MEM_S32(0x%x) = argc;\n", symbol_names_inv.at("__Argc"));
2447
printf("MEM_S32(0x%x) = argc;\n", stack_bottom);
2448
printf("uint32_t al = argc * 4; for (int i = 0; i < argc; i++) al += strlen(argv[i]) + 1;\n");
2449
printf("uint32_t arg_addr = wrapper_malloc(mem, al);\n");
2450
printf("MEM_U32(0x%x) = arg_addr;\n", symbol_names_inv.at("__Argv"));
2451
printf("MEM_U32(0x%x) = arg_addr;\n", stack_bottom + 4);
2452
printf("uint32_t arg_strpos = arg_addr + argc * 4;\n");
2453
printf("for (int i = 0; i < argc; i++) {MEM_U32(arg_addr + i * 4) = arg_strpos; uint32_t p = 0; do { MEM_S8(arg_strpos) = argv[i][p]; ++arg_strpos; } while (argv[i][p++] != '\\0');}\n");
2454
2455
printf("setup_libc_data(mem);\n");
2456
2457
//printf("gp = 0x%x;\n", gp_value); // only to recreate the outcome when ugen reads uninitialized stack memory
2458
2459
printf("int ret = f_main(mem, 0x%x", stack_bottom);
2460
Function& main_func = functions[main_addr];
2461
if (main_func.nargs >= 1) {
2462
printf(", argc");
2463
}
2464
if (main_func.nargs >= 2) {
2465
printf(", arg_addr");
2466
}
2467
printf(");\n");
2468
if (TRACE) {
2469
printf("end: fprintf(stderr, \"cnt: %%llu\\n\", cnt);\n");
2470
}
2471
printf("return ret;\n");
2472
printf("}\n");
2473
2474
for (auto& f_it : functions) {
2475
Function& f = f_it.second;
2476
uint32_t start_addr = f_it.first;
2477
uint32_t end_addr = f.end_addr;
2478
2479
if (insns[addr_to_i(start_addr)].f_livein == 0) {
2480
// Non-used function, skip
2481
continue;
2482
}
2483
2484
printf("\n");
2485
dump_function_signature(f, start_addr);
2486
printf(" {\n");
2487
printf("const uint32_t zero = 0;\n");
2488
if (!conservative) {
2489
printf("uint32_t at = 0, v1 = 0, t0 = 0, t1 = 0, t2 = 0,\n");
2490
printf("t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0,\n");
2491
printf("s6 = 0, s7 = 0, t8 = 0, t9 = 0, gp = 0, fp = 0, s8 = 0, ra = 0;\n");
2492
} else {
2493
printf("uint32_t at = 0, v1 = 0, t0 = 0, t1 = 0, t2 = 0,\n");
2494
printf("t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0, t9 = 0, gp = 0x10000, ra = 0x10000;\n");
2495
}
2496
printf("uint32_t lo = 0, hi = 0;\n");
2497
printf("int cf = 0;\n");
2498
printf("uint64_t temp64;\n");
2499
printf("uint32_t fp_dest;\n");
2500
printf("void *dest;\n");
2501
if (!f.v0_in) {
2502
printf("uint32_t v0 = 0;\n");
2503
}
2504
for (uint32_t j = f.nargs; j < 4; j++) {
2505
printf("uint32_t %s = 0;\n", r(MIPS_REG_A0 + j));
2506
}
2507
2508
for (size_t i = addr_to_i(start_addr), end_i = addr_to_i(end_addr); i < end_i; i++) {
2509
Insn& insn = insns[i];
2510
uint32_t vaddr = text_vaddr + i * 4;
2511
if (label_addresses.count(vaddr)) {
2512
printf("L%x:\n", vaddr);
2513
}
2514
dump_instr(i);
2515
}
2516
2517
printf("}\n");
2518
}
2519
/*for (size_t i = 0; i < insns.size(); i++) {
2520
Insn& insn = insns[i];
2521
uint32_t vaddr = text_vaddr + i * 4;
2522
auto fn_it = functions.find(vaddr);
2523
if (fn_it != functions.end()) {
2524
Function& f = fn_it->second;
2525
printf("}\n\n");
2526
switch (f.nret) {
2527
case 0:
2528
printf("void ");
2529
break;
2530
case 1:
2531
printf("uint32_t ");
2532
break;
2533
case 2:
2534
printf("uint64_t ");
2535
break;
2536
}
2537
auto name_it = symbol_names.find(vaddr);
2538
if (name_it != symbol_names.end()) {
2539
printf("%s", name_it->second.c_str());
2540
} else {
2541
printf("func_%x", vaddr);
2542
}
2543
printf("(uint8_t *mem, uint32_t sp");
2544
if (f.v0_in) {
2545
printf(", uint32_t %s", r(MIPS_REG_V0));
2546
}
2547
for (uint32_t i = 0; i < f.nargs; i++) {
2548
printf(", uint32_t %s", r(MIPS_REG_A0 + i));
2549
}
2550
printf(") {\n");
2551
printf("const uint32_t zero = 0;\n");
2552
printf("uint32_t at = 0, v1 = 0, t0 = 0, t1 = 0, t2 = 0,\n");
2553
printf("t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, s0 = 0, s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0,\n");
2554
printf("s6 = 0, s7 = 0, t8 = 0, t9 = 0, gp = 0, fp = 0, s8 = 0, ra = 0;\n");
2555
printf("uint32_t lo = 0, hi = 0;\n");
2556
printf("int cf = 0;\n");
2557
if (!f.v0_in) {
2558
printf("uint32_t v0 = 0;\n");
2559
}
2560
for (uint32_t j = f.nargs; j < 4; j++) {
2561
printf("uint32_t %s = 0;\n", r(MIPS_REG_A0 + j));
2562
}
2563
}
2564
if (label_addresses.count(vaddr)) {
2565
printf("L%x:\n", vaddr);
2566
}
2567
dump_instr(i);
2568
}*/
2569
}
2570
2571
static void parse_elf(const uint8_t *data, size_t file_len) {
2572
Elf32_Ehdr *ehdr;
2573
Elf32_Shdr *shdr, *str_shdr, *sym_shdr = NULL, *dynsym_shdr, *dynamic_shdr, *reginfo_shdr, *got_shdr, *sym_strtab, *sym_dynstr;
2574
int text_section_index = -1;
2575
int symtab_section_index = -1;
2576
int dynsym_section_index = -1;
2577
int reginfo_section_index = -1;
2578
int dynamic_section_index = -1;
2579
int got_section_index = -1;
2580
int rodata_section_index = -1;
2581
int data_section_index = -1;
2582
int bss_section_index = -1;
2583
uint32_t text_offset = 0;
2584
uint32_t vaddr_adj = 0;
2585
2586
if (file_len < 4 || data[0] != 0x7f || data[1] != 'E' || data[2] != 'L' || data[3] != 'F') {
2587
fprintf(stderr, "Not an ELF file.\n");
2588
exit(EXIT_FAILURE);
2589
}
2590
2591
ehdr = (Elf32_Ehdr *) data;
2592
if (ehdr->e_ident[EI_DATA] != 2 || u16be(ehdr->e_machine) != 8) {
2593
fprintf(stderr, "Not big-endian MIPS.\n");
2594
exit(EXIT_FAILURE);
2595
}
2596
2597
if (u16be(ehdr->e_shstrndx) == 0) {
2598
// (We could look at program headers instead in this case.)
2599
fprintf(stderr, "Missing section headers; stripped binaries are not yet supported.\n");
2600
exit(EXIT_FAILURE);
2601
}
2602
2603
#define SECTION(index) (Elf32_Shdr *)(data + u32be(ehdr->e_shoff) + (index) * u16be(ehdr->e_shentsize))
2604
#define STR(strtab, offset) (const char *)(data + u32be(strtab->sh_offset) + offset)
2605
2606
str_shdr = SECTION(u16be(ehdr->e_shstrndx));
2607
for (int i = 0; i < u16be(ehdr->e_shnum); i++) {
2608
shdr = SECTION(i);
2609
const char *name = STR(str_shdr, u32be(shdr->sh_name));
2610
if (strcmp(name, ".text") == 0) {
2611
text_offset = u32be(shdr->sh_offset);
2612
text_vaddr = u32be(shdr->sh_addr);
2613
vaddr_adj = text_vaddr - u32be(shdr->sh_addr);
2614
text_section_len = u32be(shdr->sh_size);
2615
text_section = data + text_offset;
2616
text_section_index = i;
2617
}
2618
if (u32be(shdr->sh_type) == SHT_SYMTAB) {
2619
symtab_section_index = i;
2620
}
2621
if (u32be(shdr->sh_type) == SHT_DYNSYM) {
2622
dynsym_section_index = i;
2623
}
2624
if (u32be(shdr->sh_type) == SHT_MIPS_REGINFO) {
2625
reginfo_section_index = i;
2626
}
2627
if (u32be(shdr->sh_type) == SHT_DYNAMIC) {
2628
dynamic_section_index = i;
2629
}
2630
if (strcmp(name, ".got") == 0) {
2631
got_section_index = i;
2632
}
2633
if (strcmp(name, ".rodata") == 0) {
2634
rodata_section_index = i;
2635
}
2636
if (strcmp(name, ".data") == 0) {
2637
data_section_index = i;
2638
}
2639
if (strcmp(name, ".bss") == 0) {
2640
bss_section_index = i;
2641
}
2642
}
2643
2644
if (text_section_index == -1) {
2645
fprintf(stderr, "Missing .text section.\n");
2646
exit(EXIT_FAILURE);
2647
}
2648
2649
if (symtab_section_index == -1 && dynsym_section_index == -1) {
2650
fprintf(stderr, "Missing .symtab or .dynsym section.\n");
2651
exit(EXIT_FAILURE);
2652
}
2653
2654
if (dynsym_section_index != -1) {
2655
if (reginfo_section_index == -1) {
2656
fprintf(stderr, "Missing .reginfo section.\n");
2657
exit(EXIT_FAILURE);
2658
}
2659
if (dynamic_section_index == -1) {
2660
fprintf(stderr, "Missing .dynamic section.\n");
2661
exit(EXIT_FAILURE);
2662
}
2663
if (got_section_index == -1) {
2664
fprintf(stderr, "Missing .got section.\n");
2665
exit(EXIT_FAILURE);
2666
}
2667
}
2668
2669
if (rodata_section_index != -1) {
2670
shdr = SECTION(rodata_section_index);
2671
uint32_t size = u32be(shdr->sh_size);
2672
rodata_section = data + u32be(shdr->sh_offset);
2673
rodata_section_len = size;
2674
rodata_vaddr = u32be(shdr->sh_addr);
2675
}
2676
2677
if (data_section_index != -1) {
2678
shdr = SECTION(data_section_index);
2679
uint32_t size = u32be(shdr->sh_size);
2680
data_section = data + u32be(shdr->sh_offset);
2681
data_section_len = size;
2682
data_vaddr = u32be(shdr->sh_addr);
2683
}
2684
2685
if (bss_section_index != -1) {
2686
shdr = SECTION(bss_section_index);
2687
uint32_t size = u32be(shdr->sh_size);
2688
bss_section_len = size;
2689
bss_vaddr = u32be(shdr->sh_addr);
2690
}
2691
2692
2693
// add symbols
2694
if (symtab_section_index != -1) {
2695
sym_shdr = SECTION(symtab_section_index);
2696
sym_strtab = SECTION(u32be(sym_shdr->sh_link));
2697
assert(0 && ".symtab not supported - use a program with .dynsym instead");
2698
2699
assert(u32be(sym_shdr->sh_entsize) == sizeof(Elf32_Sym));
2700
for (uint32_t i = 0; i < u32be(sym_shdr->sh_size); i += sizeof(Elf32_Sym)) {
2701
Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(sym_shdr->sh_offset) + i);
2702
const char *name = STR(sym_strtab, u32be(sym->st_name));
2703
uint32_t addr = u32be(sym->st_value);
2704
if (u16be(sym->st_shndx) != text_section_index || name[0] == '.') {
2705
continue;
2706
}
2707
addr += vaddr_adj;
2708
//disasm_label_add(state, name, addr, u32be(sym->st_size), true);
2709
}
2710
}
2711
2712
if (dynsym_section_index != -1) {
2713
dynsym_shdr = SECTION(dynsym_section_index);
2714
sym_dynstr = SECTION(u32be(dynsym_shdr->sh_link));
2715
reginfo_shdr = SECTION(reginfo_section_index);
2716
dynamic_shdr = SECTION(dynamic_section_index);
2717
got_shdr = SECTION(got_section_index);
2718
2719
Elf32_RegInfo *reg_info = (Elf32_RegInfo *)(data + u32be(reginfo_shdr->sh_offset));
2720
uint32_t gp_base = u32be(reg_info->ri_gp_value); // gp should have this value through the program run
2721
uint32_t got_start = 0;
2722
uint32_t local_got_no = 0;
2723
uint32_t first_got_sym = 0;
2724
uint32_t dynsym_no = 0; // section size can't be used due to alignment 16 padding
2725
2726
assert(u32be(dynamic_shdr->sh_entsize) == sizeof(Elf32_Dyn));
2727
for (uint32_t i = 0; i < u32be(dynamic_shdr->sh_size); i += sizeof(Elf32_Dyn)) {
2728
Elf32_Dyn *dyn = (Elf32_Dyn *)(data + u32be(dynamic_shdr->sh_offset) + i);
2729
if (u32be(dyn->d_tag) == DT_PLTGOT) {
2730
got_start = u32be(dyn->d_un.d_ptr);
2731
}
2732
if (u32be(dyn->d_tag) == DT_MIPS_LOCAL_GOTNO) {
2733
local_got_no = u32be(dyn->d_un.d_val);
2734
}
2735
if (u32be(dyn->d_tag) == DT_MIPS_GOTSYM) {
2736
first_got_sym = u32be(dyn->d_un.d_val);
2737
}
2738
if (u32be(dyn->d_tag) == DT_MIPS_SYMTABNO) {
2739
dynsym_no = u32be(dyn->d_un.d_val);
2740
}
2741
}
2742
2743
assert(got_start != 0);
2744
2745
// value to add to asm gp offset, for example 32752, if -32752(gp) refers to the first entry in got.
2746
uint32_t gp_adj = gp_base - got_start;
2747
assert(gp_adj < 0x10000);
2748
2749
assert(u32be(dynsym_shdr->sh_entsize) == sizeof(Elf32_Sym));
2750
uint32_t global_got_no = dynsym_no - first_got_sym;
2751
//global_got_entry *global_entries = (global_got_entry *)calloc(global_got_no, sizeof(global_got_entry));
2752
got_globals.resize(global_got_no);
2753
2754
uint32_t common_start = ~0U;
2755
vector<string> common_order;
2756
2757
for (uint32_t i = 0; i < dynsym_no; i++) {
2758
Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(dynsym_shdr->sh_offset) + i * sizeof(Elf32_Sym));
2759
const char *name = STR(sym_dynstr, u32be(sym->st_name));
2760
uint32_t addr = u32be(sym->st_value);
2761
addr += vaddr_adj;
2762
uint8_t type = ELF32_ST_TYPE(sym->st_info);
2763
if (!strcmp(name, "_procedure_table")) {
2764
procedure_table_start = addr;
2765
} else if (!strcmp(name, "_procedure_table_size")) {
2766
procedure_table_len = 40 * u32be(sym->st_value);
2767
}
2768
if ((u16be(sym->st_shndx) == SHN_MIPS_TEXT && type == STT_FUNC) ||
2769
(type == STT_OBJECT && (u16be(sym->st_shndx) == SHN_MIPS_ACOMMON || u16be(sym->st_shndx) == SHN_MIPS_DATA)))
2770
{
2771
//disasm_label_add(state, name, addr, u32be(sym->st_size), true);
2772
if (type == STT_OBJECT) {
2773
}
2774
if (u16be(sym->st_shndx) == SHN_MIPS_ACOMMON) {
2775
if (addr < common_start) {
2776
common_start = addr;
2777
}
2778
common_order.push_back(name);
2779
}
2780
if (type == STT_FUNC) {
2781
add_function(addr);
2782
if (strcmp(name, "main") == 0) {
2783
main_addr = addr;
2784
}
2785
if (strcmp(name, "_mcount") == 0) {
2786
mcount_addr = addr;
2787
}
2788
symbol_names[addr] = name;
2789
}
2790
}
2791
if (i >= first_got_sym) {
2792
uint32_t got_value = u32be(*(uint32_t *)(data + u32be(got_shdr->sh_offset) + (local_got_no + (i - first_got_sym)) * sizeof(uint32_t)));
2793
if (u16be(sym->st_shndx) == SHN_MIPS_TEXT && type == STT_FUNC) {
2794
//got_globals[i - first_got_sym] = got_value;
2795
//label_addresses.insert(got_value);
2796
got_globals[i - first_got_sym] = addr; // to include the 3 instr gp header thing
2797
label_addresses.insert(addr);
2798
} else if (type == STT_OBJECT && (u16be(sym->st_shndx) == SHN_UNDEF || u16be(sym->st_shndx) == SHN_COMMON)) {
2799
// symbol defined externally (for example in libc)
2800
got_globals[i - first_got_sym] = got_value;
2801
} else {
2802
got_globals[i - first_got_sym] = addr;
2803
}
2804
symbol_names[got_globals[i - first_got_sym]] = name;
2805
}
2806
}
2807
2808
uint32_t *local_entries = (uint32_t *)calloc(local_got_no, sizeof(uint32_t));
2809
got_locals.resize(local_got_no);
2810
for (uint32_t i = 0; i < local_got_no; i++) {
2811
uint32_t *entry = (uint32_t *)(data + u32be(got_shdr->sh_offset) + i * sizeof(uint32_t));
2812
got_locals[i] = u32be(*entry);
2813
}
2814
2815
gp_value = gp_base;
2816
gp_value_adj = gp_adj;
2817
//disasm_got_entries_set(state, gp_base, gp_adj, local_entries, local_got_no, global_entries, global_got_no);
2818
2819
//out_range.common_start = common_start;
2820
//out_range.common_order.swap(common_order);
2821
}
2822
2823
// add relocations
2824
for (int i = 0; i < u16be(ehdr->e_shnum); i++) {
2825
Elf32_Rel *prevHi = NULL;
2826
shdr = SECTION(i);
2827
if (u32be(shdr->sh_type) != SHT_REL || u32be(shdr->sh_info) != (uint32_t) text_section_index)
2828
continue;
2829
2830
if (sym_shdr == NULL) {
2831
fprintf(stderr, "Relocations without .symtab section\n");
2832
exit(EXIT_FAILURE);
2833
}
2834
2835
assert(u32be(shdr->sh_link) == (uint32_t) symtab_section_index);
2836
assert(u32be(shdr->sh_entsize) == sizeof(Elf32_Rel));
2837
for (uint32_t i = 0; i < u32be(shdr->sh_size); i += sizeof(Elf32_Rel)) {
2838
Elf32_Rel *rel = (Elf32_Rel *)(data + u32be(shdr->sh_offset) + i);
2839
uint32_t offset = text_offset + u32be(rel->r_offset);
2840
uint32_t symIndex = ELF32_R_SYM(u32be(rel->r_info));
2841
uint32_t rtype = ELF32_R_TYPE(u32be(rel->r_info));
2842
const char *symName = "0";
2843
if (symIndex != STN_UNDEF) {
2844
Elf32_Sym *sym = (Elf32_Sym *)(data + u32be(sym_shdr->sh_offset) + symIndex * sizeof(Elf32_Sym));
2845
symName = STR(sym_strtab, u32be(sym->st_name));
2846
}
2847
2848
if (rtype == R_MIPS_HI16) {
2849
if (prevHi != NULL) {
2850
fprintf(stderr, "Consecutive R_MIPS_HI16.\n");
2851
exit(EXIT_FAILURE);
2852
}
2853
prevHi = rel;
2854
continue;
2855
}
2856
if (rtype == R_MIPS_LO16) {
2857
int32_t addend = (int16_t)((data[offset + 2] << 8) + data[offset + 3]);
2858
if (prevHi != NULL) {
2859
uint32_t offset2 = text_offset + u32be(prevHi->r_offset);
2860
addend += (uint32_t)((data[offset2 + 2] << 8) + data[offset2 + 3]) << 16;
2861
//add_reloc(state, offset2, symName, addend, out_range.vaddr);
2862
}
2863
prevHi = NULL;
2864
//add_reloc(state, offset, symName, addend, out_range.vaddr);
2865
}
2866
else if (rtype == R_MIPS_26) {
2867
int32_t addend = (u32be(*(uint32_t*)(data + offset)) & ((1 << 26) - 1)) << 2;
2868
if (addend >= (1 << 27)) {
2869
addend -= 1 << 28;
2870
}
2871
//add_reloc(state, offset, symName, addend, out_range.vaddr);
2872
}
2873
else {
2874
fprintf(stderr, "Bad relocation type %d.\n", rtype);
2875
exit(EXIT_FAILURE);
2876
}
2877
}
2878
if (prevHi != NULL) {
2879
fprintf(stderr, "R_MIPS_HI16 without matching R_MIPS_LO16.\n");
2880
exit(EXIT_FAILURE);
2881
}
2882
}
2883
}
2884
#undef SECTION
2885
#undef STR
2886
2887
size_t read_file(const char *file_name, uint8_t **data) {
2888
FILE *in;
2889
uint8_t *in_buf = NULL;
2890
long file_size;
2891
long bytes_read;
2892
in = fopen(file_name, "rb");
2893
assert(in != nullptr);
2894
2895
// allocate buffer to read from offset to end of file
2896
fseek(in, 0, SEEK_END);
2897
file_size = ftell(in);
2898
assert(file_size != -1L);
2899
2900
in_buf = (uint8_t *)malloc(file_size);
2901
fseek(in, 0, SEEK_SET);
2902
2903
// read bytes
2904
bytes_read = fread(in_buf, 1, file_size, in);
2905
assert(bytes_read == file_size);
2906
2907
fclose(in);
2908
*data = in_buf;
2909
return bytes_read;
2910
}
2911
2912
int main(int argc, char *argv[]) {
2913
const char *filename = argv[1];
2914
if (strcmp(filename, "--conservative") == 0) {
2915
conservative = true;
2916
filename = argv[2];
2917
}
2918
2919
uint8_t *data;
2920
size_t len = read_file(filename, &data);
2921
parse_elf(data, len);
2922
assert(cs_open(CS_ARCH_MIPS, (cs_mode)(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &handle) == CS_ERR_OK);
2923
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
2924
disassemble();
2925
inspect_data_function_pointers(data_function_pointers, rodata_section, rodata_vaddr, rodata_section_len);
2926
inspect_data_function_pointers(data_function_pointers, data_section, data_vaddr, data_section_len);
2927
pass1();
2928
pass2();
2929
pass3();
2930
pass4();
2931
pass5();
2932
pass6();
2933
//dump();
2934
dump_c();
2935
free(data);
2936
cs_close(&handle);
2937
}
2938
2939
2940