PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
srxfixup.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "srxfixup_internal.h"
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17static const char *conffile = NULL;
18static const char *ofile = NULL;
19static const char *rfile = NULL;
20static const char *ffile = NULL;
21static unsigned int startaddr;
22static const char *entrysym = NULL;
23static unsigned int verbose = 0;
24static unsigned int dumpflag = 0;
25static unsigned int dispmod_flag = 0;
26static int irx1_flag = 0;
27static int br_conv = 0;
28static int print_config = 0;
29// clang-format off
30static const Opttable opttable[] =
31{
32 { "-v", ARG_HAVEARG_NONE, 'f', &verbose },
33 { "-d", ARG_HAVEARG_NONE, 'f', &dumpflag },
34 { "-r", ARG_HAVEARG_REQUIRED, 's', &rfile },
35 { "-o", ARG_HAVEARG_REQUIRED, 's', &ofile },
36 { "-c", ARG_HAVEARG_REQUIRED, 's', &conffile },
37 { "-f", ARG_HAVEARG_REQUIRED, 's', &ffile },
38 { "-t", ARG_HAVEARG_REQUIRED, 'h', &startaddr },
39 { "-e", ARG_HAVEARG_REQUIRED, 's', &entrysym },
40 { "-m", ARG_HAVEARG_NONE, 'f', &dispmod_flag },
41 { "--irx1", ARG_HAVEARG_NONE, 'f', &irx1_flag },
42 { "--rb", ARG_HAVEARG_NONE, 'f', &br_conv },
43 { "--relative-branch", ARG_HAVEARG_NONE, 'f', &br_conv },
44 { "--print-internal-config", ARG_HAVEARG_NONE, 'f', &print_config },
45 { NULL, 0, '\0', NULL },
46};
47static const Opttable stripopttable[] =
48{
49 { "-v", ARG_HAVEARG_NONE, 'f', &verbose },
50 { "-d", ARG_HAVEARG_NONE, 'f', &dumpflag },
51 { "-o", ARG_HAVEARG_REQUIRED, 's', &ofile },
52 { "-c", ARG_HAVEARG_REQUIRED, 's', &conffile },
53 { "-e", ARG_HAVEARG_REQUIRED, 's', &entrysym },
54 { "-m", ARG_HAVEARG_NONE, 'f', &dispmod_flag },
55 { "--irx1", ARG_HAVEARG_NONE, 'f', &irx1_flag },
56 { "--rb", ARG_HAVEARG_NONE, 'f', &br_conv },
57 { "--relative-branch", ARG_HAVEARG_NONE, 'f', &br_conv },
58 { "--print-internal-config", ARG_HAVEARG_NONE, 'f', &print_config },
59 { NULL, 0, '\0', NULL },
60};
61// clang-format on
62
63static void display_module_info(elf_file *elf);
64static void convert_relative_branch_an_section(elf_section *relsect);
65static void convert_relative_branch(elf_file *elf);
66
67void usage(const char *myname)
68{
69 printf(
70 "IOP/EE relocatable object converter\n"
71 "%s\n"
72 "usage: %s [options] <elf_input_file>\n",
73 myname,
74 myname);
75 printf(" options:\n"
76 " -v\n"
77 " -m\n"
78 " --irx1\n"
79 " -o <elf_relocatable_nosymbol_output_file>\n"
80 " -r <elf_relocatable_output_file>\n"
81 " -e <entry_point_symbol>\n"
82 " --relative-branch or --rb\n");
83 if ( verbose )
84 {
85 printf(" -t <.text start address>\n"
86 " -f <elf_fixedaddress_output_file>\n"
87 " -d<hex_flag>\n"
88 " hex_flag bits:\n"
89 " bit0: dump section table\n"
90 " bit1: dump relocation record\n"
91 " bit2: dump symbol table\n"
92 " bit3: disassemble program code\n"
93 " bit4: dump .data/.rodata/.sdata... sections by byte\n"
94 " bit5: dump .data/.rodata/.sdata... sections by half word\n"
95 " bit6: dump .data/.rodata/.sdata... sections by word\n"
96 " bit7: dump .data/.rodata/.sdata... sections by word with relocation data\n"
97 " bit8: dump file layout\n"
98 " bit9: dump .mdebug section\n");
99 }
100 if ( verbose > 1 )
101 {
102 printf(" bit12: dump srx genaration table\n"
103 " -c <config_file>\n"
104 " --print-internal-config\n");
105 }
106}
107
108void stripusage(const char *myname)
109{
110 printf(
111 "%s\n"
112 "usage: %s [options] <elf_file>\n",
113 myname,
114 myname);
115 printf(" options:\n"
116 " -v\n"
117 " -m\n"
118 " -o <elf_relocatable_nosymbol_output_file>\n"
119 " --relative-branch or --rb\n");
120}
121
122int main(int argc, char **argv)
123{
124 Srx_gen_table *srxgen_1;
125 const char *defaultconf;
126 elf_file *elf;
127 const char *myname_1;
128 const char *myname_2;
129 const char *source;
130
131 myname_1 = strrchr(*argv, '/');
132 if ( !myname_1 )
133 {
134 myname_1 = strrchr(*argv, '\\');
135 }
136 if ( myname_1 )
137 {
138 myname_2 = myname_1 + 1;
139 }
140 else
141 {
142 myname_2 = *argv;
143 }
144 if ( (strncmp(myname_2, "ee", 2) != 0) && (strncmp(myname_2, "EE", 2) != 0) )
145 {
146 defaultconf = iop_defaultconf;
147 }
148 else
149 {
150 defaultconf = ee_defaultconf;
151 }
152 if ( strlen(*argv) > 5 && !strcmp(&(*argv)[strlen(*argv) - 5], "strip") )
153 {
154 int argca;
155
156 argca = analize_arguments(stripopttable, argc, argv);
157 if ( argca != 2 )
158 {
159 Srx_gen_table *srxgen_2;
160
161 srxgen_2 = read_conf(defaultconf, conffile, print_config);
162 if ( !srxgen_2 )
163 {
164 exit(1);
165 }
166 if ( (dumpflag & 0x1000) != 0 )
167 {
168 dump_srx_gen_table(srxgen_2);
169 exit(0);
170 }
171 }
172 if ( argca <= 1 )
173 {
174 stripusage(*argv);
175 exit(1);
176 }
177 if ( argca > 2 )
178 {
179 fprintf(stderr, "Too many input file\n");
180 stripusage(*argv);
181 exit(1);
182 }
183 if ( !ofile )
184 {
185 ofile = argv[1];
186 }
187 }
188 else
189 {
190 int argcb;
191
192 argcb = analize_arguments(opttable, argc, argv);
193 if ( argcb != 2 )
194 {
195 Srx_gen_table *srxgen_3;
196
197 srxgen_3 = read_conf(defaultconf, conffile, print_config);
198 if ( !srxgen_3 )
199 {
200 exit(1);
201 }
202 if ( (dumpflag & 0x1000) != 0 )
203 {
204 dump_srx_gen_table(srxgen_3);
205 exit(0);
206 }
207 }
208 if ( argcb <= 1 )
209 {
210 usage(*argv);
211 exit(1);
212 }
213 if ( argcb > 2 )
214 {
215 fprintf(stderr, "Too many input file\n");
216 usage(*argv);
217 exit(1);
218 }
219 }
220 source = argv[1];
221 elf = read_elf(source);
222 if ( !elf )
223 {
224 exit(1);
225 }
226 if (
227 ((elf->ehp->e_flags & EF_MIPS_MACH) == EF_MIPS_MACH_5900)
228 && ((elf->ehp->e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_3) )
229 {
230 srxgen_1 = read_conf(ee_defaultconf, conffile, print_config);
231 }
232 else
233 {
234 srxgen_1 = read_conf(iop_defaultconf, conffile, print_config);
235 }
236 if ( !srxgen_1 )
237 {
238 exit(1);
239 }
240 if ( (dumpflag & 0x1000) != 0 )
241 {
242 dump_srx_gen_table(srxgen_1);
243 exit(0);
244 }
245 if ( (dumpflag & 0xFFF) != 0 )
246 {
247 print_elf(elf, dumpflag & 0xFFF);
248 exit(0);
249 }
250 elf->optdata = (void *)srxgen_1;
251 switch ( elf->ehp->e_type )
252 {
253 case ET_REL:
254 if ( convert_rel2srx(elf, entrysym, (rfile || ofile || ffile) ? 1 : 0, irx1_flag) )
255 {
256 exit(1);
257 }
258 break;
259 case ET_SCE_IOPRELEXEC:
260 case ET_SCE_IOPRELEXEC2:
261 case ET_SCE_EERELEXEC2:
262 case ET_EXEC:
263 break;
264 default:
265 fprintf(stderr, "Error: '%s' is unsupport Type Elf file(type=%x)\n", source, elf->ehp->e_type);
266 exit(1);
267 break;
268 }
269 if ( dispmod_flag )
270 {
271 display_module_info(elf);
272 }
273 switch ( elf->ehp->e_type )
274 {
275 case ET_SCE_IOPRELEXEC:
276 case ET_SCE_IOPRELEXEC2:
277 case ET_SCE_EERELEXEC2:
278 if ( br_conv )
279 {
280 convert_relative_branch(elf);
281 }
282 if ( rfile )
283 {
284 if ( layout_srx_file(elf) )
285 {
286 exit(1);
287 }
288 write_elf(elf, rfile);
289 }
290 if ( ofile )
291 {
292 strip_elf(elf);
293 if ( layout_srx_file(elf) )
294 {
295 exit(1);
296 }
297 write_elf(elf, ofile);
298 }
299 break;
300 default:
301 if ( rfile || ofile )
302 {
303 fprintf(stderr, "Error: Cannot generate IRX/ERX file. '%s' file type is ET_EXEC.\n", source);
304 exit(1);
305 }
306 break;
307 }
308 if ( ffile || startaddr != (unsigned int)(-1) )
309 {
310 switch ( elf->ehp->e_type )
311 {
312 case ET_SCE_IOPRELEXEC:
313 case ET_SCE_IOPRELEXEC2:
314 case ET_SCE_EERELEXEC2:
315 elf->ehp->e_type = ET_EXEC;
316 fixlocation_elf(elf, startaddr);
317 break;
318 default:
319 break;
320 }
321 if ( ffile )
322 {
323 if ( layout_srx_file(elf) )
324 {
325 exit(1);
326 }
327 write_elf(elf, ffile);
328 }
329 }
330 return 0;
331}
332
333static void display_module_info(elf_file *elf)
334{
335 elf_section *modsect_1;
336 elf_section *modsect_2;
337
338 modsect_1 = search_section(elf, SHT_SCE_IOPMOD);
339 if ( modsect_1 )
340 {
341 const Elf32_IopMod *iopmodinfo;
342
343 iopmodinfo = (Elf32_IopMod *)modsect_1->data;
344 if ( iopmodinfo->moduleinfo != (Elf32_Word)(-1) )
345 {
346 printf(
347 "name:%s version:%d.%d\n",
348 iopmodinfo->modulename,
349 (uint8_t)(iopmodinfo->moduleversion >> 24),
350 (uint8_t)iopmodinfo->moduleversion);
351 }
352 }
353 modsect_2 = search_section(elf, SHT_SCE_EEMOD);
354 if ( modsect_2 )
355 {
356 const Elf32_EeMod *eemodinfo;
357
358 eemodinfo = (Elf32_EeMod *)modsect_2->data;
359 if ( eemodinfo->moduleinfo != (Elf32_Word)(-1) )
360 {
361 printf(
362 "name:%s version:%d.%d\n",
363 eemodinfo->modulename,
364 (uint8_t)(eemodinfo->moduleversion >> 24),
365 (uint8_t)eemodinfo->moduleversion);
366 }
367 }
368}
369
370static void convert_relative_branch_an_section(elf_section *relsect)
371{
372 elf_syment **symp;
373 elf_rel *rp;
374 int rmcount;
375 unsigned int entrise;
376 unsigned int i;
377
378 entrise = relsect->shr.sh_size / relsect->shr.sh_entsize;
379 rp = (elf_rel *)relsect->data;
380 symp = (elf_syment **)relsect->link->data;
381 rmcount = 0;
382 for ( i = 0; i < entrise; i += 1 )
383 {
384 unsigned int type;
385 uint8_t *daddr;
386
387 if ( rp->symptr && *symp != rp->symptr )
388 {
389 fprintf(stderr, "Internal error: Illegal relocation entry\n");
390 exit(1);
391 }
392 if (
393 relsect->info->shr.sh_addr > rp->rel.r_offset
394 || rp->rel.r_offset >= relsect->info->shr.sh_size + relsect->info->shr.sh_addr )
395 {
396 fprintf(
397 stderr,
398 "Panic !! relocation #%u offset=0x%x range out (section limit addr=0x%x-0x%x)\n",
399 i,
400 rp->rel.r_offset,
401 relsect->info->shr.sh_addr,
402 relsect->info->shr.sh_size + relsect->info->shr.sh_addr);
403 exit(1);
404 }
405 daddr = &relsect->info->data[rp->rel.r_offset - relsect->info->shr.sh_addr];
406 type = rp->type;
407 if ( type )
408 {
409 if ( type == R_MIPS_26 )
410 {
411 uint32_t raddr;
412 unsigned int data;
413
414 data = *(uint32_t *)daddr;
415 if ( rp->symptr && rp->symptr->bind != STB_LOCAL )
416 {
417 fprintf(stderr, "R_MIPS_26 Unexcepted bind\n");
418 exit(1);
419 }
420 raddr = rp->rel.r_offset + relsect->info->shr.sh_addr;
421 if (
422 !((((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 18)
423 || (((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 18 == 0x3FFF )
424 {
425 int jaddr;
426
427 jaddr = (uint16_t)((((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 2);
428 if ( data >> 26 == 2 )
429 {
430 *(uint32_t *)daddr = jaddr | 0x10000000;
431 rp->type = R_MIPS_NONE;
432 rmcount += 1;
433 }
434 else if ( data >> 26 == 3 )
435 {
436 *(uint32_t *)daddr = jaddr | 0x4110000;
437 rp->type = R_MIPS_NONE;
438 rmcount += 1;
439 }
440 }
441 }
442 }
443 else
444 {
445 rmcount += 1;
446 }
447 rp += 1;
448 }
449 if ( rmcount > 0 && (entrise - rmcount) > 0 )
450 {
451 elf_rel *s;
452 elf_rel *d;
453 elf_rel *newtab;
454 unsigned int j;
455
456 newtab = (elf_rel *)calloc(entrise - rmcount, sizeof(elf_rel));
457 d = newtab;
458 s = (elf_rel *)relsect->data;
459 for ( j = 0; j < entrise; j += 1 )
460 {
461 if ( s->type )
462 {
463 memcpy(d, s, sizeof(elf_rel));
464 d += 1;
465 }
466 s += 1;
467 }
468 free(relsect->data);
469 relsect->data = (uint8_t *)newtab;
470 relsect->shr.sh_size = relsect->shr.sh_entsize * (entrise - rmcount);
471 }
472}
473
474static void convert_relative_branch(elf_file *elf)
475{
476 int i;
477
478 if ( elf->scp == NULL )
479 {
480 return;
481 }
482 for ( i = 1; i < elf->ehp->e_shnum; i += 1 )
483 {
484 if ( elf->scp[i]->shr.sh_type == SHT_REL )
485 {
486 convert_relative_branch_an_section(elf->scp[i]);
487 }
488 }
489}