1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - ELF Loader
3 File: loader_subset.c
4
5 Copyright 2006-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-17#$
14 $Rev: 8556 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include "loader_subset.h"
21
22
23 extern ELUnresolvedEntry* ELUnrEntStart;
24
25 extern u16 dbg_print_flag;
26 extern u32 unresolved_table_block_flag;
27
28
29 //Use the following statements to determine whether the processor is ARM7.
30 //#ifdef SDK_ARM7
31 //#endif /*SDK_ARM7*/
32
33
34 /*------------------------------------------------------
35 Align the addresses
36 -----------------------------------------------------*/
37 #define ALIGN( addr, align_size ) (((addr) & ~((align_size) - 1)) + (align_size))
38
39 u32 ELi_ALIGN( u32 addr, u32 align_size);
ELi_ALIGN(u32 addr,u32 align_size)40 u32 ELi_ALIGN( u32 addr, u32 align_size)
41 {
42 u32 aligned_addr;
43
44 if( (addr % align_size) == 0) {
45 aligned_addr = addr;
46 }else{
47 aligned_addr = (((addr) & ~((align_size) - 1)) + (align_size));
48 }
49
50 return aligned_addr;
51 }
52
53
54 /*------------------------------------------------------
55 Copy the content of the symbol string to the buffer.
56 -----------------------------------------------------*/
ELi_CopySymStrToBuffer(ELHandle * ElfHandle,ELShdrEx * SymStrShdrEx)57 void* ELi_CopySymStrToBuffer( ELHandle* ElfHandle, ELShdrEx* SymStrShdrEx)
58 {
59 u32 load_start;
60
61 /*Align*/
62 load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
63
64 memcpy( (void*)load_start, SymStrShdrEx->str_table, SymStrShdrEx->str_table_size);
65
66 /*Correct the size of the section header*/
67 SymStrShdrEx->Shdr.sh_size = SymStrShdrEx->str_table_size;
68
69 /*Move the buffer pointer*/
70 ElfHandle->buf_current = (void*)(load_start + SymStrShdrEx->str_table_size);
71
72 return( void*)load_start;
73 }
74
75 /*------------------------------------------------------
76 Copy the content of the section string to the buffer.
77 -----------------------------------------------------*/
ELi_CopyShStrToBuffer(ELHandle * ElfHandle,Elf32_Shdr * Shdr)78 void* ELi_CopyShStrToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr)
79 {
80 u32 load_start, i;
81 u32 total_size = 0;
82 ELShdrEx* CurrentShdrEx;
83
84 /*Align*/
85 load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
86 // load_adr = load_start;
87
88 /*Update locations where the section header references character entries*/
89 for( i=0; i<(ElfHandle->CurrentEhdr.e_shnum); i++) {
90 CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, i);
91
92 if( CurrentShdrEx->debug_flag == 1) {
93 }else{
94 CurrentShdrEx->Shdr.sh_name = total_size;
95 strcpy( (void*)(load_start+total_size), CurrentShdrEx->str);
96 total_size += (strlen( CurrentShdrEx->str) + 1);
97 }
98 }
99
100 /*Correct the size of the section header*/
101 Shdr->sh_size = total_size;
102
103 /*Move the buffer pointer*/
104 ElfHandle->buf_current = (void*)(load_start + total_size);
105
106 return( void*)load_start;
107 }
108
109 /*------------------------------------------------------
110 Copy the symbol entries together to the buffer
111 -----------------------------------------------------*/
ELi_CopySymToBuffer(ELHandle * ElfHandle)112 void* ELi_CopySymToBuffer( ELHandle* ElfHandle)
113 {
114 u32 load_start, load_adr;
115 u32 total_size = 0;
116 ELSymEx* CurrentSymEx;
117
118 /*Align*/
119 load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
120 load_adr = load_start;
121
122 CurrentSymEx = ElfHandle->SymEx;
123 while( CurrentSymEx != NULL) {
124 /*copy*/
125 memcpy( (u8*)load_adr, &(CurrentSymEx->Sym),
126 sizeof( Elf32_Sym));
127 CurrentSymEx = CurrentSymEx->next;
128 load_adr += sizeof( Elf32_Sym);
129 total_size += sizeof( Elf32_Sym);
130 // printf( "symbol found\n");
131 }
132
133 /*Move the buffer pointer*/
134 ElfHandle->buf_current = (void*)(load_start + total_size);
135
136 return( void*)load_start;
137 }
138
139 /*------------------------------------------------------
140 Copy the section to the buffer
141 -----------------------------------------------------*/
ELi_CopySectionToBuffer(ELHandle * ElfHandle,Elf32_Shdr * Shdr)142 void* ELi_CopySectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr)
143 {
144 u32 load_start;
145 Elf32_Addr sh_size;
146
147 /*Align*/
148 // load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign));
149 load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
150
151 /*Set size*/
152 sh_size = Shdr->sh_size;
153
154 /*copy*/
155 ElfHandle->ELi_ReadStub( (void*)load_start,
156 ElfHandle->FileStruct,
157 (u32)(ElfHandle->ar_head),
158 (u32)(ElfHandle->elf_offset)+(u32)(Shdr->sh_offset),
159 sh_size);
160
161 /*Move the buffer pointer*/
162 ElfHandle->buf_current = (void*)(load_start + sh_size);
163
164 /*Return the loaded header address*/
165 return (void*)load_start;
166 }
167
168
169 /*------------------------------------------------------
170 Allocate a section in the buffer (do not copy) and embed a 0 for that region.
171
172 -----------------------------------------------------*/
ELi_AllocSectionToBuffer(ELHandle * ElfHandle,Elf32_Shdr * Shdr)173 void* ELi_AllocSectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr)
174 {
175 u32 load_start;
176 Elf32_Addr sh_size;
177
178 /*Align*/
179 // load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign));
180 load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
181 /*Set size*/
182 sh_size = Shdr->sh_size;
183
184 /*Move the buffer pointer*/
185 ElfHandle->buf_current = (void*)(load_start + sh_size);
186
187 /*Embed with 0 (because .bss section is expected)*/
188 memset( (void*)load_start, 0, sh_size);
189
190 /*Return the allocated header address */
191 return (void*)load_start;
192 }
193
194
195 /*------------------------------------------------------
196 Get section header for the specified index to the buffer
197 -----------------------------------------------------*/
ELi_GetShdr(ELHandle * ElfHandle,u32 index,Elf32_Shdr * Shdr)198 void ELi_GetShdr( ELHandle* ElfHandle, u32 index, Elf32_Shdr* Shdr)
199 {
200 u32 offset;
201
202 offset = (ElfHandle->CurrentEhdr.e_shoff) + ((u32)(ElfHandle->shentsize) * index);
203
204 ElfHandle->ELi_ReadStub( Shdr,
205 ElfHandle->FileStruct,
206 (u32)(ElfHandle->ar_head),
207 (u32)(ElfHandle->elf_offset) + offset,
208 sizeof( Elf32_Shdr));
209 }
210
211 /*------------------------------------------------------
212 Get section entry for the specified index to the buffer
213 -----------------------------------------------------*/
ELi_GetSent(ELHandle * ElfHandle,u32 index,void * entry_buf,u32 offset,u32 size)214 void ELi_GetSent( ELHandle* ElfHandle, u32 index, void* entry_buf, u32 offset, u32 size)
215 {
216 Elf32_Shdr Shdr;
217 //u32 entry_adr;
218
219 ELi_GetShdr( ElfHandle, index, &Shdr);
220
221 ElfHandle->ELi_ReadStub( entry_buf,
222 ElfHandle->FileStruct,
223 (u32)(ElfHandle->ar_head),
224 (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset,
225 size);
226 }
227
228
229 /*------------------------------------------------------
230 Get the index entry for the specified section header to the buffer.
231 (Only section with a fixed entry size, such as Rel, Rela, Sym, and the like.)
232 Shdr: Specified section header
233 index: Entry number (from 0)
234 -----------------------------------------------------*/
ELi_GetEntry(ELHandle * ElfHandle,Elf32_Shdr * Shdr,u32 index,void * entry_buf)235 void ELi_GetEntry( ELHandle* ElfHandle, Elf32_Shdr* Shdr, u32 index, void* entry_buf)
236 {
237 u32 offset;
238
239 offset = (u32)(Shdr->sh_offset) + ((Shdr->sh_entsize) * index);
240
241 ElfHandle->ELi_ReadStub( entry_buf,
242 ElfHandle->FileStruct,
243 (u32)(ElfHandle->ar_head),
244 (u32)(ElfHandle->elf_offset) + offset,
245 Shdr->sh_entsize);
246 }
247
248 /*------------------------------------------------------
249 Get specified index character string of the STR section header
250
251 Shdr: Specified section header
252 index: Entry Index (from 0)
253 -----------------------------------------------------*/
ELi_GetStrAdr(ELHandle * ElfHandle,u32 strsh_index,u32 ent_index,char * str,u32 len)254 void ELi_GetStrAdr( ELHandle* ElfHandle, u32 strsh_index, u32 ent_index, char* str, u32 len)
255 {
256 /*Header address of the string entry*/
257 ELi_GetSent( ElfHandle, strsh_index, str, ent_index, len);
258 }
259
260 /*------------------------------------------------------
261 Get the length of specified index string for the STR section header
262
263 Shdr: Specified section header
264 index: Entry index (from 0)
265 -----------------------------------------------------*/
ELi_GetStrLen(ELHandle * ElfHandle,u32 index,u32 offset)266 u32 ELi_GetStrLen( ELHandle* ElfHandle, u32 index, u32 offset)
267 {
268 Elf32_Shdr Shdr;
269 char buf[1];
270 u32 count = 0;
271
272 ELi_GetShdr( ElfHandle, index, &Shdr);
273
274 ElfHandle->ELi_ReadStub( buf,
275 ElfHandle->FileStruct,
276 (u32)(ElfHandle->ar_head),
277 (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset,
278 1);
279 while( buf[0] != 0 )
280 {
281 count++;
282 ElfHandle->ELi_ReadStub( buf,
283 ElfHandle->FileStruct,
284 (u32)(ElfHandle->ar_head),
285 (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset + count,
286 1);
287 }
288 return count;
289 }
290
291 /*------------------------------------------------------
292 Create the symbol list
293
294 -----------------------------------------------------*/
ELi_BuildSymList(ELHandle * elElfDesc,u32 symsh_index,u32 ** sym_table)295 void ELi_BuildSymList( ELHandle* elElfDesc, u32 symsh_index, u32** sym_table)
296 {
297 u32 i;
298 u32 num_of_sym; //Overall symbol count
299 u16 debug_flag;
300 Elf32_Sym TestSym;
301 ELSymEx* CurrentSymEx;
302 ELShdrEx* CurrentShdrEx;
303 Elf32_Shdr SymShdr;
304 ELSymEx DmySymEx;
305 u32 sym_num = 0;
306
307 if( elElfDesc->SymExTarget == symsh_index) {
308 // printf( "%s skip.\n", __FUNCTION__);
309 return; //List already created
310 }else{
311 ELi_FreeSymList( elElfDesc, sym_table); /*Deallocate the symbol list*/
312 }
313
314 // printf( "%s build\n", __FUNCTION__);
315
316 /*Get SYMTAB section header*/
317 ELi_GetShdr( elElfDesc, symsh_index, &SymShdr);
318
319 /*Build new/old symbol correspondence table*/
320 *sym_table = (u32*)malloc( 4 * (SymShdr.sh_size / SymShdr.sh_entsize));
321
322 num_of_sym = (SymShdr.sh_size) / (SymShdr.sh_entsize); //Overall symbol count
323 elElfDesc->SymExTbl = malloc( num_of_sym * 4);
324
325 /*---------- Create ELSymEx List ----------*/
326 CurrentSymEx = &DmySymEx;
327 for( i=0; i<num_of_sym; i++) {
328
329 /*Copy symbol entry*/
330 ELi_GetEntry( elElfDesc, &SymShdr, i, &TestSym);
331
332 /*-- Set debug information flag --*/
333 CurrentShdrEx = ELi_GetShdrExfromList( elElfDesc->ShdrEx, TestSym.st_shndx);
334 if( CurrentShdrEx) {
335 debug_flag = CurrentShdrEx->debug_flag;
336 }else{
337 debug_flag = 0;
338 }/*-------------------------------*/
339
340 if( debug_flag == 1) {
341 elElfDesc->SymExTbl[i] = NULL;
342 (*sym_table)[i] = 0xFFFFFFFF;
343 }else{
344 CurrentSymEx->next = malloc( sizeof(ELSymEx));
345 CurrentSymEx = (ELSymEx*)(CurrentSymEx->next);
346
347 memcpy( &(CurrentSymEx->Sym), &TestSym, sizeof(TestSym));
348
349 elElfDesc->SymExTbl[i] = CurrentSymEx;
350
351 (*sym_table)[i] = sym_num;
352
353 sym_num++;
354
355 // printf( "sym_no: %02x ... st_shndx: %04x\n", i, CurrentSymEx->Sym.st_shndx);
356
357 /*-- Set the ELSymEx Thumb flag (Only the function symbol is required) -----*/
358 if( ELF32_ST_TYPE( CurrentSymEx->Sym.st_info) == STT_FUNC) {
359 CurrentSymEx->thumb_flag = (u16)(ELi_CodeIsThumb( elElfDesc, CurrentSymEx->Sym.st_shndx,
360 CurrentSymEx->Sym.st_value));
361 }else{
362 CurrentSymEx->thumb_flag = 0;
363 }/*--------------------------------------------------------*/
364 }
365 }
366
367 CurrentSymEx->next = NULL;
368 elElfDesc->SymEx = DmySymEx.next;
369 /*-------------------------------------------*/
370
371
372 elElfDesc->SymExTarget = symsh_index;
373 }
374
375
376 /*------------------------------------------------------
377 Deallocate the symbol list
378
379 -----------------------------------------------------*/
ELi_FreeSymList(ELHandle * elElfDesc,u32 ** sym_table)380 void ELi_FreeSymList( ELHandle* elElfDesc, u32** sym_table)
381 {
382 ELSymEx* CurrentSymEx;
383 ELSymEx* FwdSymEx;
384
385 if( elElfDesc->SymExTbl != NULL) {
386 free( elElfDesc->SymExTbl);
387 elElfDesc->SymExTbl = NULL;
388 }
389
390 /*---------- Free the ELSymEx List ----------*/
391 CurrentSymEx = elElfDesc->SymEx;
392 if( CurrentSymEx) {
393 while( CurrentSymEx->next != NULL) {
394 FwdSymEx = CurrentSymEx;
395 CurrentSymEx = CurrentSymEx->next;
396 free( FwdSymEx);
397 }
398 elElfDesc->SymEx = NULL;
399 }
400 /*-----------------------------------------*/
401
402 /* if( *sym_table) { // Deallocated by the application here and so commented out
403 free( *sym_table);
404 }*/
405
406
407 elElfDesc->SymExTarget = 0xFFFFFFFF;
408 }
409
410
411 /*------------------------------------------------------
412 Read ELSymEx of the index specified from the list.
413 -----------------------------------------------------*/
ELi_GetSymExfromList(ELSymEx * SymExStart,u32 index)414 ELSymEx* ELi_GetSymExfromList( ELSymEx* SymExStart, u32 index)
415 {
416 u32 i;
417 ELSymEx* SymEx;
418
419 SymEx = SymExStart;
420 for( i=0; i<index; i++) {
421 SymEx = (ELSymEx*)(SymEx->next);
422 if( SymEx == NULL) {
423 break;
424 }
425 }
426 return SymEx;
427 }
428
429 /*------------------------------------------------------
430 Read ELShdrx of the index specified from the list.
431 -----------------------------------------------------*/
ELi_GetShdrExfromList(ELShdrEx * ShdrExStart,u32 index)432 ELShdrEx* ELi_GetShdrExfromList( ELShdrEx* ShdrExStart, u32 index)
433 {
434 u32 i;
435 ELShdrEx* ShdrEx;
436
437 ShdrEx = ShdrExStart;
438 for( i=0; i<index; i++) {
439 ShdrEx = (ELShdrEx*)(ShdrEx->next);
440 if( ShdrEx == NULL) {
441 break;
442 }
443 }
444 return ShdrEx;
445 }
446
447
448
449 /*------------------------------------------------------
450 Determine whether the section for the specified index is debug information
451
452 <Definition of debugging information>
453 - Sections whose section name begins with .debug.
454
455 - Section, such as .rel.debug - section, where the sh_info indicates the debug information section number
456
457 -----------------------------------------------------*/
ELi_ShdrIsDebug(ELHandle * ElfHandle,u32 index)458 BOOL ELi_ShdrIsDebug( ELHandle* ElfHandle, u32 index)
459 {
460 Elf32_Shdr TmpShdr;
461 char shstr[6];
462
463 /*-- Get six characters of character string for section name --*/
464 ELi_GetShdr( ElfHandle, index, &TmpShdr);
465 ELi_GetStrAdr( ElfHandle, ElfHandle->CurrentEhdr.e_shstrndx,
466 TmpShdr.sh_name, shstr, 6);
467 /*-------------------------------------*/
468
469 if( strncmp( shstr, ".debug", 6) == 0) { /*When debugging section*/
470 return TRUE;
471 }else{ /*When relocated section relates to the debugging section*/
472 if( (TmpShdr.sh_type == SHT_REL) || (TmpShdr.sh_type == SHT_RELA)) {
473 if( ELi_ShdrIsDebug( ElfHandle, TmpShdr.sh_info) == TRUE) {
474 return TRUE;
475 }
476 }
477 }
478
479 return FALSE;
480 }
481
482
483
484 /*------------------------------------------------------
485 Checks the ElfHandle SymEx table, and determines whether the code in the specified offset of the specified index is ARM or THUMB.
486
487 (Preset ElfHandle->SymShdr and ElfHandle->SymEx.)
488
489 sh_index: Section index to be checked
490 offset: Offset in section to check
491 -----------------------------------------------------*/
ELi_CodeIsThumb(ELHandle * ElfHandle,u16 sh_index,u32 offset)492 u32 ELi_CodeIsThumb( ELHandle* ElfHandle, u16 sh_index, u32 offset)
493 {
494 u32 i;
495 u32 thumb_flag;
496 Elf32_Shdr* SymShdr;
497 char str_adr[3];
498 ELSymEx* CurrentSymEx;
499
500 /*Get symbol section header and SymEx list*/
501 SymShdr = &(ElfHandle->SymShdr);
502 CurrentSymEx = ElfHandle->SymEx;
503
504 i = 0;
505 thumb_flag = 0;
506 while( CurrentSymEx != NULL) {
507
508 if( CurrentSymEx->Sym.st_shndx == sh_index) {
509 ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, str_adr, 3);
510 if( strncmp( str_adr, "$a\0", strlen("$a\0")) == 0) {
511 thumb_flag = 0;
512 }else if( strncmp( str_adr, "$t\0", strlen("$t\0")) == 0) {
513 thumb_flag = 1;
514 }
515 if( CurrentSymEx->Sym.st_value > offset) {
516 break;
517 }
518 }
519
520 CurrentSymEx = CurrentSymEx->next;
521 i++;
522 }
523
524 return thumb_flag;
525 }
526
527
528 /*---------------------------------------------------------
529 Initialize unresolved information entries
530 --------------------------------------------------------*/
ELi_UnresolvedInfoInit(ELUnresolvedEntry * UnresolvedInfo)531 void ELi_UnresolvedInfoInit( ELUnresolvedEntry* UnresolvedInfo)
532 {
533 UnresolvedInfo->sym_str = NULL;
534 UnresolvedInfo->r_type = 0;
535 UnresolvedInfo->S_ = 0;
536 UnresolvedInfo->A_ = 0;
537 UnresolvedInfo->P_ = 0;
538 UnresolvedInfo->T_ = 0;
539 UnresolvedInfo->remove_flag = 0;
540 }
541
542 /*------------------------------------------------------
543 Delete entry from the unresolved information table
544 -----------------------------------------------------*/
ELi_RemoveUnresolvedEntry(ELUnresolvedEntry * UnrEnt)545 BOOL ELi_RemoveUnresolvedEntry( ELUnresolvedEntry* UnrEnt)
546 {
547 ELUnresolvedEntry DmyUnrEnt;
548 ELUnresolvedEntry* CurrentUnrEnt;
549
550 if( UnrEnt == NULL) {
551 return FALSE;
552 }
553
554 DmyUnrEnt.next = ELUnrEntStart;
555 CurrentUnrEnt = &DmyUnrEnt;
556
557 while( CurrentUnrEnt->next != UnrEnt) {
558 if( CurrentUnrEnt->next == NULL) {
559 return FALSE;
560 }else{
561 CurrentUnrEnt = (ELUnresolvedEntry*)(CurrentUnrEnt->next);
562 }
563 }
564
565 CurrentUnrEnt->next = UnrEnt->next;
566 free( UnrEnt->sym_str);
567 free( UnrEnt);
568 ELUnrEntStart = DmyUnrEnt.next;
569
570 return TRUE;
571 }
572
573 /*---------------------------------------------------------
574 Add entry to the unresolved information table
575 --------------------------------------------------------*/
ELi_AddUnresolvedEntry(ELUnresolvedEntry * UnrEnt)576 void ELi_AddUnresolvedEntry( ELUnresolvedEntry* UnrEnt)
577 {
578 ELUnresolvedEntry DmyUnrEnt;
579 ELUnresolvedEntry* CurrentUnrEnt;
580
581 if( !ELUnrEntStart) {
582 ELUnrEntStart = UnrEnt;
583 }else{
584 DmyUnrEnt.next = ELUnrEntStart;
585 CurrentUnrEnt = &DmyUnrEnt;
586
587 while( CurrentUnrEnt->next != NULL) {
588 CurrentUnrEnt = CurrentUnrEnt->next;
589 }
590 CurrentUnrEnt->next = (void*)UnrEnt;
591 }
592 UnrEnt->next = NULL;
593 }
594
595 /*------------------------------------------------------
596 Search for entry corresponding to specified string in the unresolved information table
597 -----------------------------------------------------*/
ELi_GetUnresolvedEntry(char * ent_name)598 ELUnresolvedEntry* ELi_GetUnresolvedEntry( char* ent_name)
599 {
600 ELUnresolvedEntry* CurrentUnrEnt;
601
602 CurrentUnrEnt = ELUnrEntStart;
603 if( CurrentUnrEnt == NULL) {
604 return NULL;
605 }
606 while( 1) {
607 if( (strcmp( CurrentUnrEnt->sym_str, ent_name) == 0)&&
608 (CurrentUnrEnt->remove_flag == 0)) {
609 break;
610 }
611 CurrentUnrEnt = (ELUnresolvedEntry*)CurrentUnrEnt->next;
612 if( CurrentUnrEnt == NULL) {
613 break;
614 }
615 }
616 return CurrentUnrEnt;
617 }
618