11 int cmp_relocs (const void *p1
, const void *p2
)
13 const struct prx_reloc
*r1
= p1
;
14 const struct prx_reloc
*r2
= p2
;
15 if (r1
->target
< r2
->target
) return -1;
16 if (r1
->target
> r2
->target
) return 1;
21 int cmp_relocs_by_addr (const void *p1
, const void *p2
)
23 const struct prx_reloc
*r1
= p1
;
24 const struct prx_reloc
*r2
= p2
;
25 if (r1
->vaddr
< r2
->vaddr
) return -1;
26 if (r1
->vaddr
> r2
->vaddr
) return 1;
31 int check_apply_relocs (struct prx
*p
)
33 struct prx_reloc
*r
, *lastxhi
= NULL
;
34 struct elf_program
*offsbase
;
35 struct elf_program
*addrbase
;
36 uint32 index
, addend
, base
, temp
;
37 uint32 hiaddr
, loaddr
;
40 for (index
= 0; index
< p
->relocnum
; index
++) {
41 r
= &p
->relocs
[index
];
42 if (r
->offsbase
>= p
->phnum
) {
43 error (__FILE__
": invalid offset base for relocation (%d)", r
->offsbase
);
47 if (r
->addrbase
>= p
->phnum
) {
48 error (__FILE__
": invalid address base for relocation (%d)", r
->offsbase
);
52 offsbase
= &p
->programs
[r
->offsbase
];
53 addrbase
= &p
->programs
[r
->addrbase
];
55 r
->vaddr
= r
->offset
+ offsbase
->vaddr
;
56 if (!prx_inside_progfile (offsbase
, r
->vaddr
, 4)) {
57 error (__FILE__
": relocation points to invalid address (0x%08X)", r
->vaddr
);
62 for (index
= 0; index
< p
->relocnum
; index
++) {
63 r
= &p
->relocs
[index
];
64 offsbase
= &p
->programs
[r
->offsbase
];
65 addrbase
= &p
->programs
[r
->addrbase
];
67 addend
= read_uint32_le (&offsbase
->data
[r
->offset
]);
75 r
->target
= (r
->offset
+ offsbase
->vaddr
) & 0xF0000000;
76 r
->target
= (((addend
& 0x3FFFFFF) << 2) | r
->target
) + addrbase
->vaddr
;
77 addend
= (addend
& ~0x3FFFFFF) | (r
->target
>> 2);
78 if (!prx_inside_progfile (addrbase
, r
->target
, 8)) {
79 error (__FILE__
": mips26 reference out of range at 0x%08X (0x%08X)", r
->vaddr
, r
->target
);
81 write_uint32_le ((uint8
*)&offsbase
->data
[r
->offset
], addend
);
85 while (++index
< p
->relocnum
) {
86 if (p
->relocs
[index
].type
!= R_MIPS_HI16
) break;
87 if (p
->relocs
[index
].offsbase
!= r
->offsbase
) {
88 error (__FILE__
": changed offset base");
91 if (p
->relocs
[index
].addrbase
!= r
->addrbase
) {
92 error (__FILE__
": changed offset base");
95 temp
= read_uint32_le (&offsbase
->data
[p
->relocs
[index
].offset
]) & 0xFFFF;
96 if (temp
!= (addend
& 0xFFFF)) {
97 error (__FILE__
": changed hi");
102 if (index
== p
->relocnum
) {
103 error (__FILE__
": hi16 without matching lo16");
107 if (p
->relocs
[index
].type
!= R_MIPS_LO16
||
108 p
->relocs
[index
].offsbase
!= r
->offsbase
||
109 p
->relocs
[index
].addrbase
!= r
->addrbase
) {
110 error (__FILE__
": hi16 without matching lo16");
114 temp
= read_uint32_le (&offsbase
->data
[p
->relocs
[index
].offset
]) & 0xFFFF;
115 if (temp
& 0x8000) temp
|= ~0xFFFF;
117 r
->target
= ((addend
& 0xFFFF) << 16) + addrbase
->vaddr
+ temp
;
118 addend
= temp
& 0xFFFF;
119 if (!prx_inside_progmem (addrbase
, r
->target
, 1)) {
120 error (__FILE__
": hi16 reference out of range at 0x%08X (0x%08X)", r
->vaddr
, r
->target
);
123 loaddr
= r
->target
& 0xFFFF;
124 hiaddr
= (((r
->target
>> 15) + 1) >> 1) & 0xFFFF;
126 while (base
< index
) {
127 p
->relocs
[base
].target
= r
->target
;
128 temp
= (read_uint32_le (&offsbase
->data
[p
->relocs
[base
].offset
]) & ~0xFFFF) | hiaddr
;
129 write_uint32_le ((uint8
*) &offsbase
->data
[p
->relocs
[base
].offset
], temp
);
133 while (index
< p
->relocnum
) {
134 temp
= read_uint32_le (&offsbase
->data
[p
->relocs
[index
].offset
]);
135 if ((temp
& 0xFFFF) != addend
) break;
136 if (p
->relocs
[index
].type
!= R_MIPS_LO16
) break;
137 if (p
->relocs
[index
].offsbase
!= r
->offsbase
) break;
138 if (p
->relocs
[index
].addrbase
!= r
->addrbase
) break;
140 p
->relocs
[index
].target
= r
->target
;
142 temp
= (temp
& ~0xFFFF) | loaddr
;
143 write_uint32_le ((uint8
*) &offsbase
->data
[p
->relocs
[index
].offset
], temp
);
149 r
->target
= ((addend
& 0xFFFF) << 16) + addrbase
->vaddr
+ r
->addend
;
150 addend
= (addend
& ~0xFFFF) | ((((r
->target
>> 15) + 1) >> 1) & 0xFFFF);
151 if (!prx_inside_progmem (addrbase
, r
->target
, 1)) {
152 error (__FILE__
": xhi16 reference out of range at 0x%08X (0x%08X)", r
->vaddr
, r
->target
);
154 write_uint32_le ((uint8
*)&offsbase
->data
[r
->offset
], addend
);
160 r
->target
= (addend
& 0xFFFF) + addrbase
->vaddr
;
162 if ((lastxhi
->target
& 0xFFFF) == (r
->target
& 0xFFFF) &&
163 lastxhi
->addrbase
== r
->addrbase
&&
164 lastxhi
->offsbase
== r
->offsbase
) {
165 r
->target
= lastxhi
->target
;
168 addend
= (addend
& ~0xFFFF) | (r
->target
& 0xFFFF);
169 if (!prx_inside_progmem (addrbase
, r
->target
, 1)) {
170 error (__FILE__
": lo16 reference out of range at 0x%08X (0x%08X)", r
->vaddr
, r
->target
);
172 write_uint32_le ((uint8
*)&offsbase
->data
[r
->offset
], addend
);
176 r
->target
= addend
+ addrbase
->vaddr
;
178 /*if (!inside_progmem (addrbase, r->target, 1)) {
179 error (__FILE__ ": mips32 reference out of range at 0x%08X (0x%08X)", r->vaddr, r->target);
181 write_uint32_le ((uint8
*)&offsbase
->data
[r
->offset
], addend
);
185 error (__FILE__
": invalid reference type %d", r
->type
);
192 p
->relocsbyaddr
= xmalloc (p
->relocnum
* sizeof (struct prx_reloc
));
193 memcpy (p
->relocsbyaddr
, p
->relocs
, p
->relocnum
* sizeof (struct prx_reloc
));
195 qsort (p
->relocs
, p
->relocnum
, sizeof (struct prx_reloc
), &cmp_relocs
);
196 qsort (p
->relocsbyaddr
, p
->relocnum
, sizeof (struct prx_reloc
), &cmp_relocs_by_addr
);
203 uint32
count_relocs_b (uint32 prgidx
, const uint8
*data
, uint32 size
)
206 uint8 part1s
, part2s
;
207 uint32 block1s
, block2s
;
208 uint8 block1
[256], block2
[256];
209 uint32 temp1
, temp2
, part1
, part2
;
210 uint32 count
= 0, nbits
;
213 for (nbits
= 1; (1 << nbits
) < prgidx
; nbits
++) {
215 error (__FILE__
": invalid number of bits for indexes");
220 if (read_uint16_le (data
) != 0) {
221 error (__FILE__
": invalid header for relocation");
232 memcpy (block1
, data
, block1s
);
238 memcpy (block2
, data
, block2s
);
245 uint32 cmd
= read_uint16_le (data
);
246 temp1
= (cmd
<< (16 - part1s
)) & 0xFFFF;
247 temp1
= (temp1
>> (16 -part1s
)) & 0xFFFF;
250 if (temp1
>= block1s
) {
251 error (__FILE__
": invalid index for the first part");
254 part1
= block1
[temp1
];
255 if ((part1
& 0x06) == 0x06) {
256 error (__FILE__
": invalid size");
260 data
+= part1
& 0x06;
262 if ((part1
& 0x01) == 0) {
263 if ((part1
& 0x06) == 2) {
264 error (__FILE__
": invalid size of part1");
268 temp2
= (cmd
<< (16 - (part1s
+ nbits
+ part2s
))) & 0xFFFF;
269 temp2
= (temp2
>> (16 - part2s
)) & 0xFFFF;
270 if (temp2
>= block2s
) {
271 error (__FILE__
": invalid index for the second part");
275 part2
= block2
[temp2
];
277 switch (part1
& 0x38) {
286 error (__FILE__
": invalid addendum size");
291 case 1: case 2: case 3:
292 case 4: case 5: case 6: case 7:
298 error (__FILE__
": invalid relocation type %d", part2
);
308 int load_relocs_b (struct elf_program
*programs
, struct prx_reloc
*out
, uint32 prgidx
, const uint8
*data
, uint32 size
)
312 uint8 part1s
, part2s
;
313 uint32 block1s
, block2s
;
314 uint8 block1
[256], block2
[256];
316 uint32 part1
, part2
, lastpart2
;
317 uint32 addend
= 0, offset
= 0;
318 uint32 offsbase
= 0xFFFFFFFF;
323 for (nbits
= 1; (1 << nbits
) < prgidx
; nbits
++) {
333 memcpy (block1
, data
, block1s
);
339 memcpy (block2
, data
, block2s
);
347 uint32 cmd
= read_uint16_le (data
);
348 temp1
= (cmd
<< (16 - part1s
)) & 0xFFFF;
349 temp1
= (temp1
>> (16 -part1s
)) & 0xFFFF;
352 part1
= block1
[temp1
];
354 if ((part1
& 0x01) == 0) {
355 offsbase
= (cmd
<< (16 - part1s
- nbits
)) & 0xFFFF;
356 offsbase
= (offsbase
>> (16 - nbits
)) & 0xFFFF;
357 if (!(offsbase
< prgidx
)) {
358 error (__FILE__
": invalid offset base");
362 offset
= cmd
>> (part1s
+ nbits
);
363 if ((part1
& 0x06) == 0) continue;
364 offset
= read_uint32_le (data
);
367 temp2
= (cmd
<< (16 - (part1s
+ nbits
+ part2s
))) & 0xFFFF;
368 temp2
= (temp2
>> (16 - part2s
)) & 0xFFFF;
370 addrbase
= (cmd
<< (16 - part1s
- nbits
)) & 0xFFFF;
371 addrbase
= (addrbase
>> (16 - nbits
)) & 0xFFFF;
372 if (!(addrbase
< prgidx
)) {
373 error (__FILE__
": invalid address base");
376 part2
= block2
[temp2
];
378 switch (part1
& 0x06) {
382 cmd
>>= part1s
+ part2s
+ nbits
;
385 cmd
>>= part1s
+ part2s
+ nbits
;
390 if (cmd
& 0x8000) cmd
|= ~0xFFFF;
391 cmd
= (cmd
>> (part1s
+ part2s
+ nbits
)) << 16;
392 cmd
|= read_uint16_le (data
);
397 offset
= read_uint32_le (data
);
402 if (!(offset
< programs
[offsbase
].filesz
)) {
403 error (__FILE__
": invalid relocation offset");
407 switch (part1
& 0x38) {
412 if ((lastpart2
^ 0x04) != 0) {
417 addend
= read_uint16_le (data
);
424 out
[count
].addrbase
= addrbase
;
425 out
[count
].offsbase
= offsbase
;
426 out
[count
].offset
= offset
;
427 out
[count
].extra
= 0;
431 out
[count
++].type
= R_MIPS_32
;
436 out
[count
++].type
= R_MIPS_26
;
439 if (addend
& 0x8000) addend
|= ~0xFFFF;
440 out
[count
].addend
= addend
;
441 out
[count
++].type
= R_MIPSX_HI16
;
445 out
[count
++].type
= R_MIPS_LO16
;
448 out
[count
++].type
= R_MIPSX_J26
;
451 out
[count
++].type
= R_MIPSX_JAL26
;
461 int load_relocs (struct prx
*p
)
463 uint32 i
, ret
, count
= 0;
465 for (i
= 0; i
< p
->shnum
; i
++) {
466 struct elf_section
*section
= &p
->sections
[i
];
467 if (section
->type
== SHT_PRXRELOC
) {
468 count
+= section
->size
>> 3;
471 for (i
= 0; i
< p
->phnum
; i
++) {
472 struct elf_program
*program
= &p
->programs
[i
];
473 if (program
->type
== PT_PRXRELOC
) {
474 count
+= program
->filesz
>> 3;
475 } else if (program
->type
== PT_PRXRELOC2
) {
476 ret
= count_relocs_b (i
, program
->data
, program
->filesz
);
484 error (__FILE__
": no relocation found");
489 p
->relocs
= (struct prx_reloc
*) xmalloc (count
* sizeof (struct prx_reloc
));
490 memset (p
->relocs
, 0, count
* sizeof (struct prx_reloc
));
493 for (i
= 0; i
< p
->shnum
; i
++) {
494 struct elf_section
*section
= &p
->sections
[i
];
495 if (section
->type
== SHT_PRXRELOC
) {
498 offset
= section
->offset
;
499 secsize
= section
->size
>> 3;
500 for (j
= 0; j
< secsize
; j
++) {
501 p
->relocs
[count
].offset
= read_uint32_le (&p
->data
[offset
]);
502 p
->relocs
[count
].type
= p
->data
[offset
+ 4];
503 p
->relocs
[count
].offsbase
= p
->data
[offset
+ 5];
504 p
->relocs
[count
].addrbase
= p
->data
[offset
+ 6];
505 p
->relocs
[count
].extra
= p
->data
[offset
+ 7];
513 for (i
= 0; i
< p
->phnum
; i
++) {
514 struct elf_program
*program
= &p
->programs
[i
];
515 if (program
->type
== PT_PRXRELOC
) {
518 offset
= program
->offset
;
519 progsize
= program
->filesz
>> 3;
520 for (j
= 0; j
< progsize
; j
++) {
521 p
->relocs
[count
].offset
= read_uint32_le (&p
->data
[offset
]);
522 p
->relocs
[count
].type
= p
->data
[offset
+ 4];
523 p
->relocs
[count
].offsbase
= p
->data
[offset
+ 5];
524 p
->relocs
[count
].addrbase
= p
->data
[offset
+ 6];
525 p
->relocs
[count
].extra
= p
->data
[offset
+ 7];
530 } else if (program
->type
== PT_PRXRELOC2
) {
531 ret
= load_relocs_b (p
->programs
, &p
->relocs
[count
], i
, program
->data
, program
->filesz
);
539 if (!check_apply_relocs (p
)) return 0;
544 void free_relocs (struct prx
*p
)
551 free (p
->relocsbyaddr
);
552 p
->relocsbyaddr
= NULL
;
557 uint32
prx_findreloc (struct prx
*p
, uint32 target
)
559 uint32 first
, last
, i
;
562 last
= p
->relocnum
- 1;
563 while (first
< last
) {
564 i
= (first
+ last
) / 2;
565 if (p
->relocs
[i
].target
< target
) {
575 uint32
prx_findrelocbyaddr (struct prx
*p
, uint32 vaddr
)
577 uint32 first
, last
, i
;
580 last
= p
->relocnum
- 1;
581 while (first
< last
) {
582 i
= (first
+ last
) / 2;
583 if (p
->relocsbyaddr
[i
].vaddr
< vaddr
) {
594 void print_relocs (struct prx
*p
)
597 report ("\nRelocs:\n");
598 for (i
= 0; i
< p
->relocnum
; i
++) {
599 const char *type
= "unk";
601 switch (p
->relocs
[i
].type
) {
602 case R_MIPSX_HI16
: type
= "xhi16"; break;
603 case R_MIPSX_J26
: type
= "xj26"; break;
604 case R_MIPSX_JAL26
: type
= "xjal26"; break;
605 case R_MIPS_16
: type
= "mips16"; break;
606 case R_MIPS_26
: type
= "mips26"; break;
607 case R_MIPS_32
: type
= "mips32"; break;
608 case R_MIPS_HI16
: type
= "hi16"; break;
609 case R_MIPS_LO16
: type
= "lo16"; break;
610 case R_MIPS_NONE
: type
= "none"; break;
612 report (" Type: %8s Vaddr: 0x%08X Target: 0x%08X Addend: 0x%08X\n",
613 type
, p
->relocs
[i
].vaddr
, p
->relocs
[i
].target
, p
->relocs
[i
].addend
);