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-18#$
14   $Rev: 8573 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "loader_subset.h"
22 
23 
24 extern ELUnresolvedEntry*    ELUnrEntStart;
25 
26 extern u16        dbg_print_flag;
27 extern u32        unresolved_table_block_flag;
28 
29 
30 //Use the following statements to determine whether the processor is ARM7.
31 //#ifdef  SDK_ARM7
32 //#endif    /*SDK_ARM7*/
33 
34 
35 /*------------------------------------------------------
36   Align the addresses
37  -----------------------------------------------------*/
38 #define ALIGN( addr, align_size ) (((addr)  & ~((align_size) - 1)) + (align_size))
39 
40 static u32 ELi_ALIGN( u32 addr, u32 align_size);
ELi_ALIGN(u32 addr,u32 align_size)41 u32 ELi_ALIGN( u32 addr, u32 align_size)
42 {
43     u32 aligned_addr;
44 
45     if( (addr % align_size) == 0) {
46         aligned_addr = addr;
47     }else{
48         aligned_addr = (((addr) & ~((align_size) - 1)) + (align_size));
49     }
50 
51     return aligned_addr;
52 }
53 
54 
55 /*------------------------------------------------------
56   Copy the section to the buffer
57  -----------------------------------------------------*/
ELi_CopySectionToBuffer(ELHandle * ElfHandle,Elf32_Shdr * Shdr)58 void* ELi_CopySectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr)
59 {
60     u32         load_start;
61     Elf32_Addr    sh_size;
62 
63     /*Align*/
64 //    load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign));
65     load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
66     /*Set size*/
67     sh_size = Shdr->sh_size;
68 
69     /*copy*/
70     ElfHandle->ELi_ReadStub( (void*)load_start,
71                              ElfHandle->FileStruct,
72                              (u32)(ElfHandle->ar_head),
73                              (u32)(ElfHandle->elf_offset)+(u32)(Shdr->sh_offset),
74                              sh_size);
75 
76     /*Move the buffer pointer*/
77     ElfHandle->buf_current = (void*)(load_start + sh_size);
78 
79     /*Return the loaded header address*/
80     return (void*)load_start;
81 }
82 
83 
84 /*------------------------------------------------------
85   Allocate a section in the buffer (do not copy) and embed a 0 for that region.
86 
87  -----------------------------------------------------*/
ELi_AllocSectionToBuffer(ELHandle * ElfHandle,Elf32_Shdr * Shdr)88 void* ELi_AllocSectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr)
89 {
90     u32            load_start;
91     Elf32_Addr    sh_size;
92 
93     /*Align*/
94 //    load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign));
95     load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4);
96     /*Set size*/
97     sh_size = Shdr->sh_size;
98 
99     /*Move the buffer pointer*/
100     ElfHandle->buf_current = (void*)(load_start + sh_size);
101 
102     /*Embed with 0 (because .bss section is expected)*/
103     memset( (void*)load_start, 0, sh_size);
104 
105     /*Return the allocated header address  */
106     return (void*)load_start;
107 }
108 
109 
110 /*------------------------------------------------------
111   Get section header for the specified index to the buffer
112  -----------------------------------------------------*/
ELi_GetShdr(ELHandle * ElfHandle,u32 index,Elf32_Shdr * Shdr)113 void ELi_GetShdr( ELHandle* ElfHandle, u32 index, Elf32_Shdr* Shdr)
114 {
115     u32 offset;
116 
117     offset = (ElfHandle->CurrentEhdr.e_shoff) + ((u32)(ElfHandle->shentsize) * index);
118 
119     ElfHandle->ELi_ReadStub( Shdr,
120                              ElfHandle->FileStruct,
121                              (u32)(ElfHandle->ar_head),
122                              (u32)(ElfHandle->elf_offset) + offset,
123                              sizeof( Elf32_Shdr));
124 }
125 
126 /*------------------------------------------------------
127   Get section entry for the specified index to the buffer
128  -----------------------------------------------------*/
ELi_GetSent(ELHandle * ElfHandle,u32 index,void * entry_buf,u32 offset,u32 size)129 void ELi_GetSent( ELHandle* ElfHandle, u32 index, void* entry_buf, u32 offset, u32 size)
130 {
131     Elf32_Shdr    Shdr;
132     //u32            entry_adr;
133 
134     ELi_GetShdr( ElfHandle, index, &Shdr);
135 
136     ElfHandle->ELi_ReadStub( entry_buf,
137                              ElfHandle->FileStruct,
138                              (u32)(ElfHandle->ar_head),
139                              (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset,
140                              size);
141 }
142 
143 
144 /*------------------------------------------------------
145   Get specified index entry gpt the specified section header to the buffer.
146     (Only section with a fixed entry size, such as Rel, Rela, Sym, and the like.)
147     Shdr: Specified section header
148     index: Entry number (from 0)
149  -----------------------------------------------------*/
ELi_GetEntry(ELHandle * ElfHandle,Elf32_Shdr * Shdr,u32 index,void * entry_buf)150 void ELi_GetEntry( ELHandle* ElfHandle, Elf32_Shdr* Shdr, u32 index, void* entry_buf)
151 {
152     u32 offset;
153 
154     offset = (u32)(Shdr->sh_offset) + ((Shdr->sh_entsize) * index);
155 
156     ElfHandle->ELi_ReadStub( entry_buf,
157                              ElfHandle->FileStruct,
158                              (u32)(ElfHandle->ar_head),
159                              (u32)(ElfHandle->elf_offset) + offset,
160                              Shdr->sh_entsize);
161 }
162 
163 /*------------------------------------------------------
164   Get specified index character string of the STR section header
165 
166     Shdr: Specified section header
167     index: Entry index (from 0)
168  -----------------------------------------------------*/
ELi_GetStrAdr(ELHandle * ElfHandle,u32 strsh_index,u32 ent_index,char * str,u32 len)169 void ELi_GetStrAdr( ELHandle* ElfHandle, u32 strsh_index, u32 ent_index, char* str, u32 len)
170 {
171     /*Header address of the string entry*/
172     ELi_GetSent( ElfHandle, strsh_index, str, ent_index, len);
173 }
174 
175 /*------------------------------------------------------
176   Redefine symbol.
177 
178     <Rel section header>
179     RelShdr->sh_link: Symbol section number
180     RelShdr->sh_info: Target section number (ex.: Representing .text of rel.text)
181 
182     <Rel entry>
183     Rel->r_offset: Offset address in target section.
184     ELF32_R_SYM( Rel->r_info): Symbol entry number.
185     ELF32_R_TYPE( Rel->r_info): Relocate type.
186 
187     <Sym section header>
188     SymShdr->sh_link: Character string table section number of symbol
189 
190     <Sym entry>
191     Sym->st_name : Character string entry number of symbol
192     Sym->st_value : Offset address in section to which the symbol belongs
193     Sym->st_size : Size in section to which the symbol belongs
194     Sym->st_shndx: Section number to which the symbol belongs
195     ELF32_ST_BIND (Sym->st_info) : Bind (Local or Global)
196     ELF32_ST_TYPE( Sym->st_info) : Type (Target associated with the symbol)
197  -----------------------------------------------------*/
ELi_RelocateSym(ELHandle * ElfHandle,u32 relsh_index)198 void ELi_RelocateSym( ELHandle* ElfHandle, u32 relsh_index)
199 {
200     u32                    i;
201     u32                    num_of_sym;        //Overall symbol count
202     u32                    num_of_rel;        //Number of symbols that should be redefined
203     Elf32_Shdr             RelOrRelaShdr;    //REL or RELA section header
204     Elf32_Rela            CurrentRela;    //REL or RELA entry copy destination
205     Elf32_Shdr*         SymShdr;
206     ELSymEx*            CurrentSymEx;
207     ELSymEx*            FwdSymEx;
208     ELSymEx                DmySymEx;
209     ELShdrEx*            TargetShdrEx;
210     ELShdrEx*            CurrentShdrEx;
211     u32                    relocation_adr;
212     char                sym_str[128];
213     u32                    copy_size;
214     ELAdrEntry*            CurrentAdrEntry;
215     u32                    sym_loaded_adr;
216     ELAdrEntry*            ExportAdrEntry;
217     u32                    thumb_func_flag;
218     ELUnresolvedEntry    UnresolvedInfo;
219     ELUnresolvedEntry*    UnrEnt;
220     u32                    unresolved_num = 0;
221 
222     /*Get REL or RELA section header*/
223     ELi_GetShdr( ElfHandle, relsh_index, &RelOrRelaShdr);
224 
225     /*REL section and SYM section have 1:1 correspondence.*/
226     ELi_GetShdr( ElfHandle, RelOrRelaShdr.sh_link, &(ElfHandle->SymShdr));
227     SymShdr = &(ElfHandle->SymShdr);
228     if( dbg_print_flag == 1) {
229         printf( "SymShdr->link:%02x, SymShdr->info:%02x\n",
230                 (int)(SymShdr->sh_link), (int)(SymShdr->sh_info));
231     }
232 
233     /*Target section EX header*/
234     TargetShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, RelOrRelaShdr.sh_info);
235 
236     num_of_rel = (RelOrRelaShdr.sh_size) / (RelOrRelaShdr.sh_entsize);    //Number of symbols that should be redefined
237     num_of_sym = (SymShdr->sh_size) / (SymShdr->sh_entsize);    //Overall symbol count
238 
239     /*---------- Create ELSymEx List  ----------*/
240     CurrentSymEx = &DmySymEx;
241     for( i=0; i<num_of_sym; i++) {
242         CurrentSymEx->next = (void*)(malloc( sizeof(ELSymEx)));
243         CurrentSymEx = (ELSymEx*)(CurrentSymEx->next);
244 
245         /*Copy symbol entry*/
246         ELi_GetEntry( ElfHandle, SymShdr, i, &(CurrentSymEx->Sym));
247 
248         /*Set debug information flag*/
249         CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, CurrentSymEx->Sym.st_shndx);
250         if( CurrentShdrEx) {
251             CurrentSymEx->debug_flag = CurrentShdrEx->debug_flag;
252         }else{
253             CurrentSymEx->debug_flag = 0;
254         }
255 
256 //        printf( "sym_no: %02x ... st_shndx: %04x\n", i, CurrentSymEx->Sym.st_shndx);
257     }
258     CurrentSymEx->next = NULL;
259     ElfHandle->SymEx = DmySymEx.next;
260     /*-------------------------------------------*/
261 
262     /*----- Set the ELSymEx Thumb flag (Only the function symbol is required) -----*/
263     CurrentSymEx = ElfHandle->SymEx;
264     for( i=0; i<num_of_sym; i++) {
265         if( ELF32_ST_TYPE( CurrentSymEx->Sym.st_info) == STT_FUNC) {
266             CurrentSymEx->thumb_flag = (u16)(ELi_CodeIsThumb( ElfHandle, CurrentSymEx->Sym.st_shndx,
267                                                            CurrentSymEx->Sym.st_value));
268         }else{
269             CurrentSymEx->thumb_flag = 0;
270         }
271         CurrentSymEx = CurrentSymEx->next;
272     }
273     /*---------------------------------------------------------------*/
274 
275     /*--- Redefine symbols that must be redefined ---*/
276     for( i=0; i<num_of_rel; i++) {
277 
278         /*- Get Rel or Rela Entry -*/
279         ELi_GetEntry( ElfHandle, &RelOrRelaShdr, i, &CurrentRela);
280 
281         if( RelOrRelaShdr.sh_type == SHT_REL) {
282             CurrentRela.r_addend = 0;
283         }
284         /*-----------------------------*/
285 
286         /*Get symbol Ex entry*/
287         CurrentSymEx = ELi_GetSymExfromList( ElfHandle->SymEx,
288                                              ELF32_R_SYM( CurrentRela.r_info));
289 
290         if( CurrentSymEx->debug_flag == 1) {            /*When it is debugging information*/
291         }else{                                            /*When not debugging information*/
292             /**/
293             ELi_UnresolvedInfoInit( &UnresolvedInfo);
294             /*Rewritten address (Called P in the specifications)*/
295             relocation_adr = (TargetShdrEx->loaded_adr) + (CurrentRela.r_offset);
296             UnresolvedInfo.r_type = ELF32_R_TYPE( CurrentRela.r_info);
297             UnresolvedInfo.A_ = (CurrentRela.r_addend);
298             UnresolvedInfo.P_ = (relocation_adr);
299             UnresolvedInfo.sh_type = (RelOrRelaShdr.sh_type);
300 
301             /*Identify the symbol address*/
302             if( CurrentSymEx->Sym.st_shndx == SHN_UNDEF) {
303                 /*Search from address table*/
304                 ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, sym_str, 128);
305                 CurrentAdrEntry = EL_GetAdrEntry( sym_str);
306                 if( CurrentAdrEntry) {
307                     sym_loaded_adr = (u32)(CurrentAdrEntry->adr);
308                     /*THUMB function flag (called T in the specifications) to differentiate THUMB or ARM*/
309                     thumb_func_flag = CurrentAdrEntry->thumb_flag;
310                     if( dbg_print_flag == 1) {
311                         printf( "\n symbol found %s : %8x\n", sym_str, (int)(sym_loaded_adr));
312                     }
313                 }else{
314                     /*Error when not found (Cannot resolve S_ and T_)*/
315                     copy_size = (u32)strlen( sym_str) + 1;
316                     UnresolvedInfo.sym_str = (char*)(malloc( copy_size));
317                     //MI_CpuCopy8( sym_str, UnresolvedInfo.sym_str, copy_size);
318                     memcpy( UnresolvedInfo.sym_str, sym_str, copy_size);
319 
320                     /*Added to global unresolved table*/
321                     copy_size = sizeof( ELUnresolvedEntry);
322                     UnrEnt = (ELUnresolvedEntry*)(malloc( copy_size));
323                     //MI_CpuCopy8( &UnresolvedInfo, UnrEnt, copy_size);
324                     memcpy( UnrEnt, &UnresolvedInfo, copy_size);
325 
326                     if( unresolved_table_block_flag == 0) {    //If adding to the table is not prohibited
327                         ELi_AddUnresolvedEntry( UnrEnt);
328                     }
329 
330                     unresolved_num++;    /*Count number of unresolved symbols*/
331                     if( dbg_print_flag == 1) {
332                          printf( "WARNING! cannot find symbol : %s\n", sym_str);
333                     }
334                 }
335             }else{
336                 /*Get Ex header of section where symbol belongs*/
337                 CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, CurrentSymEx->Sym.st_shndx);
338                 sym_loaded_adr = CurrentShdrEx->loaded_adr;
339                 sym_loaded_adr += CurrentSymEx->Sym.st_value;    //sym_loaded_adr is called S in the specifications
340                 /*THUMB function flag (called T in the specifications) to differentiate THUMB or ARM*/
341                 thumb_func_flag = CurrentSymEx->thumb_flag;
342             }
343 
344             if( !UnresolvedInfo.sym_str) {        /*Symbol cannot be resolved if sym_str is not set*/
345                 /*Set to same variable name as in the specifications*/
346                 UnresolvedInfo.S_ = (sym_loaded_adr);
347                 UnresolvedInfo.T_ = (thumb_func_flag);
348 
349                 /*--------------- Resolve symbol (Execute Relocation) ---------------*/
350 //                CurrentSymEx->relocation_val = ELi_DoRelocate( &UnresolvedInfo);
351                 /*------------------------------------------------------------*/
352             }
353         }
354     }
355     /*-----------------------------------*/
356     /*--- Made GLOBAL symbol in library public to address table ---*/
357     for( i=0; i<num_of_sym; i++) {
358         CurrentSymEx = ELi_GetSymExfromList( ElfHandle->SymEx, i);
359         /*When global and the related section exist in the library*/
360         if( ((ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_GLOBAL) ||
361             (ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_WEAK) ||
362             (ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_MW_SPECIFIC))&&
363             (CurrentSymEx->Sym.st_shndx != SHN_UNDEF)) {
364 
365             ExportAdrEntry = (ELAdrEntry*)(malloc( sizeof(ELAdrEntry)));    /*Memory allocation*/
366 
367             ExportAdrEntry->next = NULL;
368 
369             ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, sym_str, 128);
370             copy_size = (u32)strlen( sym_str) + 1;
371             ExportAdrEntry->name = (char*)(malloc( copy_size));
372             //MI_CpuCopy8( sym_str, ExportAdrEntry->name, copy_size);
373             memcpy( ExportAdrEntry->name, sym_str, copy_size);
374 
375             CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, CurrentSymEx->Sym.st_shndx);
376             //There are cases where Sym.st_value is adjusted to enable determination of ARM/Thumb with odd/even numbers, so delete the adjustment to attain the net value.
377             ExportAdrEntry->adr = (void*)(CurrentShdrEx->loaded_adr + ((CurrentSymEx->Sym.st_value)&0xFFFFFFFE));
378             ExportAdrEntry->func_flag = (u16)(ELF32_ST_TYPE( CurrentSymEx->Sym.st_info));
379             ExportAdrEntry->thumb_flag = CurrentSymEx->thumb_flag;
380 
381             if( EL_GetAdrEntry( ExportAdrEntry->name) == NULL) {    //If not in
382                 if( dbg_print_flag == 1) {
383                     printf( "Add Entry : %s(0x%x), func=%d, thumb=%d\n",
384                                 ExportAdrEntry->name,
385                                 (int)(ExportAdrEntry->adr),
386                                 ExportAdrEntry->func_flag,
387                                 ExportAdrEntry->thumb_flag);
388                 }
389                 EL_AddAdrEntry( ExportAdrEntry);    //registration
390             }
391         }
392     }
393     /*----------------------------------------------------------------*/
394 
395     /*---------- Free the ELSymEx List  ----------*/
396     CurrentSymEx = ElfHandle->SymEx;
397     if( CurrentSymEx) {
398         while( CurrentSymEx->next != NULL) {
399             FwdSymEx = CurrentSymEx;
400             CurrentSymEx = CurrentSymEx->next;
401             free( FwdSymEx);
402         }
403         ElfHandle->SymEx = NULL;
404     }
405     /*-----------------------------------------*/
406 
407     /* After completing relocation */
408     if( unresolved_num == 0) {
409         ElfHandle->process = EL_RELOCATED;
410     }
411 }
412 
413 /*------------------------------------------------------
414     makelst-specific function
415     Register global items to address table from the symbol section
416 
417  -----------------------------------------------------*/
ELi_DiscriminateGlobalSym(ELHandle * ElfHandle,u32 symsh_index)418 void ELi_DiscriminateGlobalSym( ELHandle* ElfHandle, u32 symsh_index)
419 {
420     u32                    i;
421     u32                    num_of_sym;
422     Elf32_Shdr            CurrentSymShdr;
423     Elf32_Shdr*         SymShdr;        //SYM section header
424     ELSymEx*            CurrentSymEx;
425     ELSymEx*            FwdSymEx;
426     ELSymEx                DmySymEx;
427     ELShdrEx*            CurrentShdrEx;
428     ELAdrEntry*            ExportAdrEntry;
429     char                sym_str[128];
430     u32                    copy_size;
431 
432     /*Get SYM section header*/
433     ELi_GetShdr( ElfHandle, symsh_index, &CurrentSymShdr);
434     SymShdr = &CurrentSymShdr;
435 
436     num_of_sym = (SymShdr->sh_size) / (SymShdr->sh_entsize);    //Overall symbol count
437 
438     /*---------- Create ELSymEx List  ----------*/
439     CurrentSymEx = &DmySymEx;
440     for( i=0; i<num_of_sym; i++) {
441         CurrentSymEx->next = (void*)(malloc( sizeof(ELSymEx)));
442         CurrentSymEx = (ELSymEx*)(CurrentSymEx->next);
443 
444         /*Copy symbol entry*/
445         ELi_GetEntry( ElfHandle, SymShdr, i, &(CurrentSymEx->Sym));
446 
447         /*Set debug information flag*/
448         CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, CurrentSymEx->Sym.st_shndx);
449         if( CurrentShdrEx) {
450             CurrentSymEx->debug_flag = CurrentShdrEx->debug_flag;
451         }else{
452             CurrentSymEx->debug_flag = 0;
453         }
454 
455 //        printf( "sym_no: %02x ... st_shndx: %04x\n", i, CurrentSymEx->Sym.st_shndx);
456     }
457     CurrentSymEx->next = NULL;
458     ElfHandle->SymEx = DmySymEx.next;
459     /*-------------------------------------------*/
460 
461     /*----- Set the ELSymEx Thumb flag (Only the function symbol is required) -----*/
462     CurrentSymEx = ElfHandle->SymEx;
463     for( i=0; i<num_of_sym; i++) {
464         if( ELF32_ST_TYPE( CurrentSymEx->Sym.st_info) == STT_FUNC) {
465             CurrentSymEx->thumb_flag = (u16)(ELi_CodeIsThumb( ElfHandle, CurrentSymEx->Sym.st_shndx,
466                                                            CurrentSymEx->Sym.st_value));
467         }else{
468             CurrentSymEx->thumb_flag = 0;
469         }
470         CurrentSymEx = CurrentSymEx->next;
471     }
472     /*---------------------------------------------------------------*/
473     /*--- Made GLOBAL symbol in library public to address table ---*/
474     for( i=0; i<num_of_sym; i++) {
475         CurrentSymEx = ELi_GetSymExfromList( ElfHandle->SymEx, i);
476         /*When global and the related section exist in the library*/
477         if( ((ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_GLOBAL) ||
478             (ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_WEAK) ||
479             (ELF32_ST_BIND( CurrentSymEx->Sym.st_info) == STB_MW_SPECIFIC))&&
480             (CurrentSymEx->Sym.st_shndx != SHN_UNDEF)) {
481 
482             ExportAdrEntry = (ELAdrEntry*)(malloc( sizeof(ELAdrEntry)));    /*Memory allocation*/
483 
484             ExportAdrEntry->next = NULL;
485 
486             ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, sym_str, 128);
487             copy_size = (u32)strlen( sym_str) + 1;
488             ExportAdrEntry->name = (char*)(malloc( copy_size));
489             //MI_CpuCopy8( sym_str, ExportAdrEntry->name, copy_size);
490             memcpy( ExportAdrEntry->name, sym_str, copy_size);
491 
492             if( (CurrentSymEx->Sym.st_shndx) < SHN_LORESERVE) { //When there is a related section
493                 if( (CurrentSymEx->Sym.st_shndx == SHN_ABS)) {
494                     //There are cases where Sym.st_value is adjusted to enable determination of ARM/Thumb with odd/even numbers, so delete the adjustment to attain the net value.
495                     ExportAdrEntry->adr = (void*)((CurrentSymEx->Sym.st_value)&0xFFFFFFFE);
496                 }else{
497                     CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, CurrentSymEx->Sym.st_shndx);
498                     //There are cases where Sym.st_value is adjusted to enable determination of ARM/Thumb with odd/even numbers, so delete the adjustment to attain the net value.
499                     ExportAdrEntry->adr = (void*)(CurrentShdrEx->loaded_adr + ((CurrentSymEx->Sym.st_value)&0xFFFFFFFE));
500                 }
501             ExportAdrEntry->func_flag = (u16)(ELF32_ST_TYPE( CurrentSymEx->Sym.st_info));
502             ExportAdrEntry->thumb_flag = CurrentSymEx->thumb_flag;
503 
504             if( EL_GetAdrEntry( ExportAdrEntry->name) == NULL) {    //If not in
505                 if( dbg_print_flag == 1) {
506                     printf( "Add Entry : %s(0x%x), func=%d, thumb=%d\n",
507                                 ExportAdrEntry->name,
508                                 (int)(ExportAdrEntry->adr),
509                                 ExportAdrEntry->func_flag,
510                                 ExportAdrEntry->thumb_flag);
511                 }
512                 EL_AddAdrEntry( ExportAdrEntry);    //registration
513             }
514             }
515         }
516     }
517     /*----------------------------------------------------------------*/
518 
519     /*---------- Free the ELSymEx List  ----------*/
520     CurrentSymEx = ElfHandle->SymEx;
521     if( CurrentSymEx) {
522         while( CurrentSymEx->next != NULL) {
523             FwdSymEx = CurrentSymEx;
524             CurrentSymEx = CurrentSymEx->next;
525             free( FwdSymEx);
526         }
527         ElfHandle->SymEx = NULL;
528     }
529     /*-----------------------------------------*/
530 }
531 
532 
533 /*------------------------------------------------------
534   Resolve symbol based on unresolved information
535 
536     It is necessary to know all of the r_type, S_, A_, P_, and T_
537  -----------------------------------------------------*/
538 #define _S_    (UnresolvedInfo->S_)
539 #define _A_    (UnresolvedInfo->A_)
540 #define _P_    (UnresolvedInfo->P_)
541 #define _T_    (UnresolvedInfo->T_)
ELi_DoRelocate(ELUnresolvedEntry * UnresolvedInfo)542 u32    ELi_DoRelocate( ELUnresolvedEntry* UnresolvedInfo)
543 {
544     s32 signed_val;
545     u32 relocation_val = 0;
546     u32 relocation_adr;
547 
548     relocation_adr = _P_;
549 
550     switch( (UnresolvedInfo->r_type)) {
551       case R_ARM_PC24:
552       case R_ARM_PLT32:
553       case R_ARM_CALL:
554       case R_ARM_JUMP24:
555         if( UnresolvedInfo->sh_type == SHT_REL) {
556             _A_ = (((*(vu32*)relocation_adr)|0xFF800000) << 2);    //Generally, this should be -8
557         }
558         signed_val = (( (s32)(_S_) + _A_) | (s32)(_T_)) - (s32)(_P_);
559         if( _T_) {        /*Jump from ARM to Thumb with BLX instruction (If less than v5, there must be a way to change a BX instruction into a BL instruction in a veneer)*/
560             relocation_val = (0xFA000000) | ((signed_val>>2) & 0x00FFFFFF) | (((signed_val>>1) & 0x1)<<24);
561         }else{            /*Jump from ARM to ARM using the BL instruction*/
562             signed_val >>= 2;
563             relocation_val = (*(vu32*)relocation_adr & 0xFF000000) | (signed_val & 0x00FFFFFF);
564         }
565         *(vu32*)relocation_adr = relocation_val;
566         break;
567       case R_ARM_ABS32:
568         relocation_val = (( _S_ + _A_) | _T_);
569         *(vu32*)relocation_adr = relocation_val;
570         break;
571       case R_ARM_REL32:
572         relocation_val = (( _S_ + _A_) | _T_) - _P_;
573         *(vu32*)relocation_adr = relocation_val;
574         break;
575       case R_ARM_LDR_PC_G0:
576         signed_val = ( (s32)(_S_) + _A_) - (s32)(_P_);
577         signed_val >>= 2;
578         relocation_val = (*(vu32*)relocation_adr & 0xFF000000) | (signed_val & 0x00FFFFFF);
579         *(vu32*)relocation_adr = relocation_val;
580         break;
581       case R_ARM_ABS16:
582       case R_ARM_ABS12:
583       case R_ARM_THM_ABS5:
584       case R_ARM_ABS8:
585         relocation_val = _S_ + _A_;
586         *(vu32*)relocation_adr = relocation_val;
587         break;
588       case R_ARM_THM_PC22:/*Different Name: R_ARM_THM_CALL*/
589         if( UnresolvedInfo->sh_type == SHT_REL) {
590             _A_ = (((*(vu16*)relocation_adr & 0x07FF)<<11) + ((*((vu16*)(relocation_adr)+1)) & 0x07FF));
591             _A_ = (_A_ | 0xFFC00000) << 1;    //Generally, this should be -4 (Because the PC is the current instruction address +4)
592         }
593         signed_val = (( (s32)(_S_) + _A_) | (s32)(_T_)) - (s32)(_P_);
594         signed_val >>= 1;
595         if( _T_) {    /*Jump from Thumb to Thumb using the BL instruction*/
596             relocation_val = ((*(vu16*)relocation_adr & 0xF800) | ((signed_val>>11) & 0x07FF)) +
597                                    ((((*((vu16*)(relocation_adr)+1)) & 0xF800) | (signed_val & 0x07FF)) << 16);
598         }else{        /*Jump from Thumb to ARM with BLX instruction (If less than v5, there must be a way to change a BX instruction into a BL instruction in a veneer)*/
599             if( (signed_val & 0x1)) {    //Come here when _P_ is not 4-byte aligned
600                 signed_val += 1;
601             }
602             relocation_val = ((*(vu16*)relocation_adr & 0xF800) | ((signed_val>>11) & 0x07FF)) +
603                                    ((((*((vu16*)(relocation_adr)+1)) & 0xE800) | (signed_val & 0x07FF)) << 16);
604         }
605         *(vu16*)relocation_adr = (vu16)relocation_val;
606         *((vu16*)relocation_adr+1) = (vu16)((u32)(relocation_val) >> 16);
607         break;
608       case R_ARM_THM_JUMP24:
609         break;
610       default:
611         if( dbg_print_flag == 1) {
612             printf( "ERROR! : unsupported relocation type!\n");
613         }
614         break;
615     }
616 
617     return relocation_val;
618 }
619 #undef _S_
620 #undef _A_
621 #undef _P_
622 #undef _T_
623 
624 /*------------------------------------------------------
625   Read ELSymEx of the index specified from the list.
626  -----------------------------------------------------*/
ELi_GetSymExfromList(ELSymEx * SymExStart,u32 index)627 ELSymEx* ELi_GetSymExfromList( ELSymEx* SymExStart, u32 index)
628 {
629     u32         i;
630     ELSymEx*    SymEx;
631 
632     SymEx = SymExStart;
633     for( i=0; i<index; i++) {
634         SymEx = (ELSymEx*)(SymEx->next);
635         if( SymEx == NULL) {
636             break;
637         }
638     }
639     return SymEx;
640 }
641 
642 /*------------------------------------------------------
643   Read ELShdrx of the index specified from the list.
644  -----------------------------------------------------*/
ELi_GetShdrExfromList(ELShdrEx * ShdrExStart,u32 index)645 ELShdrEx* ELi_GetShdrExfromList( ELShdrEx* ShdrExStart, u32 index)
646 {
647     u32         i;
648     ELShdrEx*    ShdrEx;
649 
650     ShdrEx = ShdrExStart;
651     for( i=0; i<index; i++) {
652         ShdrEx = (ELShdrEx*)(ShdrEx->next);
653         if( ShdrEx == NULL) {
654             break;
655         }
656     }
657     return ShdrEx;
658 }
659 
660 
661 
662 /*------------------------------------------------------
663   Determine whether the section for the specified index is debug information
664 
665 <Definition of debugging information>
666 - Sections whose section name begins with .debug.
667 
668 - Section, such as .rel.debug - section, where the sh_info indicates the debug information section number
669 
670  -----------------------------------------------------*/
ELi_ShdrIsDebug(ELHandle * ElfHandle,u32 index)671 BOOL ELi_ShdrIsDebug( ELHandle* ElfHandle, u32 index)
672 {
673     Elf32_Shdr    TmpShdr;
674     char        shstr[6];
675 
676     /*-- Get six characters of character string for section name --*/
677     ELi_GetShdr( ElfHandle, index, &TmpShdr);
678     ELi_GetStrAdr( ElfHandle, ElfHandle->CurrentEhdr.e_shstrndx,
679                    TmpShdr.sh_name, shstr, 6);
680     /*-------------------------------------*/
681 
682     if( strncmp( shstr, ".debug", 6) == 0) {    /*When debugging section*/
683         return TRUE;
684     }else{                        /*When relocated section relates to the debugging section*/
685         if( (TmpShdr.sh_type == SHT_REL) || (TmpShdr.sh_type == SHT_RELA)) {
686             if( ELi_ShdrIsDebug( ElfHandle, TmpShdr.sh_info) == TRUE) {
687                 return TRUE;
688             }
689         }
690     }
691 
692     return FALSE;
693 }
694 
695 
696 
697 /*------------------------------------------------------
698   Check the ElfHandle SymEx table, and determine whether the code in the specified offset of the specified index is ARM or THUMB
699 
700   (Preset ElfHandle->SymShdr and ElfHandle->SymEx.)
701 
702     sh_index: Section index to be checked
703     offset: Offset in section to check
704  -----------------------------------------------------*/
ELi_CodeIsThumb(ELHandle * ElfHandle,u16 sh_index,u32 offset)705 u32 ELi_CodeIsThumb( ELHandle* ElfHandle, u16 sh_index, u32 offset)
706 {
707     u32            i;
708     u32            thumb_flag;
709     Elf32_Shdr*    SymShdr;
710     char        str_adr[3];
711     ELSymEx*    CurrentSymEx;
712 
713     /*Get symbol section header and SymEx list*/
714     SymShdr = &(ElfHandle->SymShdr);
715     CurrentSymEx = ElfHandle->SymEx;
716 
717     i = 0;
718     thumb_flag = 0;
719     while( CurrentSymEx != NULL) {
720 
721         if( CurrentSymEx->Sym.st_shndx == sh_index) {
722             ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, str_adr, 3);
723             if( strncmp( str_adr, "$a\0", strlen("$a\0")) == 0) {
724                 thumb_flag = 0;
725             }else if( strncmp( str_adr, "$t\0", strlen("$t\0")) == 0) {
726                 thumb_flag = 1;
727             }
728             if( CurrentSymEx->Sym.st_value > offset) {
729                 break;
730             }
731         }
732 
733         CurrentSymEx = CurrentSymEx->next;
734         i++;
735     }
736 
737     return thumb_flag;
738 }
739 
740 
741 /*---------------------------------------------------------
742  Initialize unresolved information entries
743  --------------------------------------------------------*/
ELi_UnresolvedInfoInit(ELUnresolvedEntry * UnresolvedInfo)744 void ELi_UnresolvedInfoInit( ELUnresolvedEntry* UnresolvedInfo)
745 {
746     UnresolvedInfo->sym_str = NULL;
747     UnresolvedInfo->r_type = 0;
748     UnresolvedInfo->S_ = 0;
749     UnresolvedInfo->A_ = 0;
750     UnresolvedInfo->P_ = 0;
751     UnresolvedInfo->T_ = 0;
752     UnresolvedInfo->remove_flag = 0;
753 }
754 
755 /*------------------------------------------------------
756   Delete entry from the unresolved information table
757  -----------------------------------------------------*/
ELi_RemoveUnresolvedEntry(ELUnresolvedEntry * UnrEnt)758 BOOL ELi_RemoveUnresolvedEntry( ELUnresolvedEntry* UnrEnt)
759 {
760     ELUnresolvedEntry    DmyUnrEnt;
761     ELUnresolvedEntry*    CurrentUnrEnt;
762 
763     if( UnrEnt == NULL) {
764         return FALSE;
765     }
766 
767     DmyUnrEnt.next = ELUnrEntStart;
768     CurrentUnrEnt = &DmyUnrEnt;
769 
770     while( CurrentUnrEnt->next != UnrEnt) {
771         if( CurrentUnrEnt->next == NULL) {
772             return FALSE;
773         }else{
774             CurrentUnrEnt = (ELUnresolvedEntry*)(CurrentUnrEnt->next);
775         }
776     }
777 
778     CurrentUnrEnt->next = UnrEnt->next;
779     free( UnrEnt->sym_str);
780     free( UnrEnt);
781     ELUnrEntStart = DmyUnrEnt.next;
782 
783     return TRUE;
784 }
785 
786 /*---------------------------------------------------------
787  Add entry to the unresolved information table
788  --------------------------------------------------------*/
ELi_AddUnresolvedEntry(ELUnresolvedEntry * UnrEnt)789 void ELi_AddUnresolvedEntry( ELUnresolvedEntry* UnrEnt)
790 {
791     ELUnresolvedEntry    DmyUnrEnt;
792     ELUnresolvedEntry*    CurrentUnrEnt;
793 
794     if( !ELUnrEntStart) {
795         ELUnrEntStart = UnrEnt;
796     }else{
797         DmyUnrEnt.next = ELUnrEntStart;
798         CurrentUnrEnt = &DmyUnrEnt;
799 
800         while( CurrentUnrEnt->next != NULL) {
801             CurrentUnrEnt = CurrentUnrEnt->next;
802         }
803         CurrentUnrEnt->next = (void*)UnrEnt;
804     }
805     UnrEnt->next = NULL;
806 }
807 
808 /*------------------------------------------------------
809   Search for entry corresponding to specified string in the unresolved information table
810  -----------------------------------------------------*/
ELi_GetUnresolvedEntry(char * ent_name)811 ELUnresolvedEntry* ELi_GetUnresolvedEntry( char* ent_name)
812 {
813     ELUnresolvedEntry* CurrentUnrEnt;
814 
815     CurrentUnrEnt = ELUnrEntStart;
816     if( CurrentUnrEnt == NULL) {
817         return NULL;
818     }
819     while( 1) {
820         if( (strcmp( CurrentUnrEnt->sym_str, ent_name) == 0)&&
821             (CurrentUnrEnt->remove_flag == 0)) {
822             break;
823         }
824         CurrentUnrEnt = (ELUnresolvedEntry*)CurrentUnrEnt->next;
825         if( CurrentUnrEnt == NULL) {
826             break;
827         }
828     }
829     return CurrentUnrEnt;
830 }
831