/*---------------------------------------------------------------------------* Project: TwlSDK - ELF Loader File: loader_subset.c Copyright 2006-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-17#$ $Rev: 8556 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include "loader_subset.h" extern ELUnresolvedEntry* ELUnrEntStart; extern u16 dbg_print_flag; extern u32 unresolved_table_block_flag; //Use the following statements to determine whether the processor is ARM7. //#ifdef SDK_ARM7 //#endif /*SDK_ARM7*/ /*------------------------------------------------------ Align the addresses -----------------------------------------------------*/ #define ALIGN( addr, align_size ) (((addr) & ~((align_size) - 1)) + (align_size)) u32 ELi_ALIGN( u32 addr, u32 align_size); u32 ELi_ALIGN( u32 addr, u32 align_size) { u32 aligned_addr; if( (addr % align_size) == 0) { aligned_addr = addr; }else{ aligned_addr = (((addr) & ~((align_size) - 1)) + (align_size)); } return aligned_addr; } /*------------------------------------------------------ Copy the content of the symbol string to the buffer. -----------------------------------------------------*/ void* ELi_CopySymStrToBuffer( ELHandle* ElfHandle, ELShdrEx* SymStrShdrEx) { u32 load_start; /*Align*/ load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4); memcpy( (void*)load_start, SymStrShdrEx->str_table, SymStrShdrEx->str_table_size); /*Correct the size of the section header*/ SymStrShdrEx->Shdr.sh_size = SymStrShdrEx->str_table_size; /*Move the buffer pointer*/ ElfHandle->buf_current = (void*)(load_start + SymStrShdrEx->str_table_size); return( void*)load_start; } /*------------------------------------------------------ Copy the content of the section string to the buffer. -----------------------------------------------------*/ void* ELi_CopyShStrToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr) { u32 load_start, i; u32 total_size = 0; ELShdrEx* CurrentShdrEx; /*Align*/ load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4); // load_adr = load_start; /*Update locations where the section header references character entries*/ for( i=0; i<(ElfHandle->CurrentEhdr.e_shnum); i++) { CurrentShdrEx = ELi_GetShdrExfromList( ElfHandle->ShdrEx, i); if( CurrentShdrEx->debug_flag == 1) { }else{ CurrentShdrEx->Shdr.sh_name = total_size; strcpy( (void*)(load_start+total_size), CurrentShdrEx->str); total_size += (strlen( CurrentShdrEx->str) + 1); } } /*Correct the size of the section header*/ Shdr->sh_size = total_size; /*Move the buffer pointer*/ ElfHandle->buf_current = (void*)(load_start + total_size); return( void*)load_start; } /*------------------------------------------------------ Copy the symbol entries together to the buffer -----------------------------------------------------*/ void* ELi_CopySymToBuffer( ELHandle* ElfHandle) { u32 load_start, load_adr; u32 total_size = 0; ELSymEx* CurrentSymEx; /*Align*/ load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4); load_adr = load_start; CurrentSymEx = ElfHandle->SymEx; while( CurrentSymEx != NULL) { /*copy*/ memcpy( (u8*)load_adr, &(CurrentSymEx->Sym), sizeof( Elf32_Sym)); CurrentSymEx = CurrentSymEx->next; load_adr += sizeof( Elf32_Sym); total_size += sizeof( Elf32_Sym); // printf( "symbol found\n"); } /*Move the buffer pointer*/ ElfHandle->buf_current = (void*)(load_start + total_size); return( void*)load_start; } /*------------------------------------------------------ Copy the section to the buffer -----------------------------------------------------*/ void* ELi_CopySectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr) { u32 load_start; Elf32_Addr sh_size; /*Align*/ // load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign)); load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4); /*Set size*/ sh_size = Shdr->sh_size; /*copy*/ ElfHandle->ELi_ReadStub( (void*)load_start, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset)+(u32)(Shdr->sh_offset), sh_size); /*Move the buffer pointer*/ ElfHandle->buf_current = (void*)(load_start + sh_size); /*Return the loaded header address*/ return (void*)load_start; } /*------------------------------------------------------ Allocate a section in the buffer (do not copy) and embed a 0 for that region. -----------------------------------------------------*/ void* ELi_AllocSectionToBuffer( ELHandle* ElfHandle, Elf32_Shdr* Shdr) { u32 load_start; Elf32_Addr sh_size; /*Align*/ // load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), (Shdr->sh_addralign)); load_start = ELi_ALIGN( ((u32)(ElfHandle->buf_current)), 4); /*Set size*/ sh_size = Shdr->sh_size; /*Move the buffer pointer*/ ElfHandle->buf_current = (void*)(load_start + sh_size); /*Embed with 0 (because .bss section is expected)*/ memset( (void*)load_start, 0, sh_size); /*Return the allocated header address */ return (void*)load_start; } /*------------------------------------------------------ Get section header for the specified index to the buffer -----------------------------------------------------*/ void ELi_GetShdr( ELHandle* ElfHandle, u32 index, Elf32_Shdr* Shdr) { u32 offset; offset = (ElfHandle->CurrentEhdr.e_shoff) + ((u32)(ElfHandle->shentsize) * index); ElfHandle->ELi_ReadStub( Shdr, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset) + offset, sizeof( Elf32_Shdr)); } /*------------------------------------------------------ Get section entry for the specified index to the buffer -----------------------------------------------------*/ void ELi_GetSent( ELHandle* ElfHandle, u32 index, void* entry_buf, u32 offset, u32 size) { Elf32_Shdr Shdr; //u32 entry_adr; ELi_GetShdr( ElfHandle, index, &Shdr); ElfHandle->ELi_ReadStub( entry_buf, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset, size); } /*------------------------------------------------------ Get the index entry for the specified section header to the buffer. (Only section with a fixed entry size, such as Rel, Rela, Sym, and the like.) Shdr: Specified section header index: Entry number (from 0) -----------------------------------------------------*/ void ELi_GetEntry( ELHandle* ElfHandle, Elf32_Shdr* Shdr, u32 index, void* entry_buf) { u32 offset; offset = (u32)(Shdr->sh_offset) + ((Shdr->sh_entsize) * index); ElfHandle->ELi_ReadStub( entry_buf, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset) + offset, Shdr->sh_entsize); } /*------------------------------------------------------ Get specified index character string of the STR section header Shdr: Specified section header index: Entry Index (from 0) -----------------------------------------------------*/ void ELi_GetStrAdr( ELHandle* ElfHandle, u32 strsh_index, u32 ent_index, char* str, u32 len) { /*Header address of the string entry*/ ELi_GetSent( ElfHandle, strsh_index, str, ent_index, len); } /*------------------------------------------------------ Get the length of specified index string for the STR section header Shdr: Specified section header index: Entry index (from 0) -----------------------------------------------------*/ u32 ELi_GetStrLen( ELHandle* ElfHandle, u32 index, u32 offset) { Elf32_Shdr Shdr; char buf[1]; u32 count = 0; ELi_GetShdr( ElfHandle, index, &Shdr); ElfHandle->ELi_ReadStub( buf, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset, 1); while( buf[0] != 0 ) { count++; ElfHandle->ELi_ReadStub( buf, ElfHandle->FileStruct, (u32)(ElfHandle->ar_head), (u32)(ElfHandle->elf_offset) + (u32)(Shdr.sh_offset) + offset + count, 1); } return count; } /*------------------------------------------------------ Create the symbol list -----------------------------------------------------*/ void ELi_BuildSymList( ELHandle* elElfDesc, u32 symsh_index, u32** sym_table) { u32 i; u32 num_of_sym; //Overall symbol count u16 debug_flag; Elf32_Sym TestSym; ELSymEx* CurrentSymEx; ELShdrEx* CurrentShdrEx; Elf32_Shdr SymShdr; ELSymEx DmySymEx; u32 sym_num = 0; if( elElfDesc->SymExTarget == symsh_index) { // printf( "%s skip.\n", __FUNCTION__); return; //List already created }else{ ELi_FreeSymList( elElfDesc, sym_table); /*Deallocate the symbol list*/ } // printf( "%s build\n", __FUNCTION__); /*Get SYMTAB section header*/ ELi_GetShdr( elElfDesc, symsh_index, &SymShdr); /*Build new/old symbol correspondence table*/ *sym_table = (u32*)malloc( 4 * (SymShdr.sh_size / SymShdr.sh_entsize)); num_of_sym = (SymShdr.sh_size) / (SymShdr.sh_entsize); //Overall symbol count elElfDesc->SymExTbl = malloc( num_of_sym * 4); /*---------- Create ELSymEx List ----------*/ CurrentSymEx = &DmySymEx; for( i=0; iShdrEx, TestSym.st_shndx); if( CurrentShdrEx) { debug_flag = CurrentShdrEx->debug_flag; }else{ debug_flag = 0; }/*-------------------------------*/ if( debug_flag == 1) { elElfDesc->SymExTbl[i] = NULL; (*sym_table)[i] = 0xFFFFFFFF; }else{ CurrentSymEx->next = malloc( sizeof(ELSymEx)); CurrentSymEx = (ELSymEx*)(CurrentSymEx->next); memcpy( &(CurrentSymEx->Sym), &TestSym, sizeof(TestSym)); elElfDesc->SymExTbl[i] = CurrentSymEx; (*sym_table)[i] = sym_num; sym_num++; // printf( "sym_no: %02x ... st_shndx: %04x\n", i, CurrentSymEx->Sym.st_shndx); /*-- Set the ELSymEx Thumb flag (Only the function symbol is required) -----*/ if( ELF32_ST_TYPE( CurrentSymEx->Sym.st_info) == STT_FUNC) { CurrentSymEx->thumb_flag = (u16)(ELi_CodeIsThumb( elElfDesc, CurrentSymEx->Sym.st_shndx, CurrentSymEx->Sym.st_value)); }else{ CurrentSymEx->thumb_flag = 0; }/*--------------------------------------------------------*/ } } CurrentSymEx->next = NULL; elElfDesc->SymEx = DmySymEx.next; /*-------------------------------------------*/ elElfDesc->SymExTarget = symsh_index; } /*------------------------------------------------------ Deallocate the symbol list -----------------------------------------------------*/ void ELi_FreeSymList( ELHandle* elElfDesc, u32** sym_table) { ELSymEx* CurrentSymEx; ELSymEx* FwdSymEx; if( elElfDesc->SymExTbl != NULL) { free( elElfDesc->SymExTbl); elElfDesc->SymExTbl = NULL; } /*---------- Free the ELSymEx List ----------*/ CurrentSymEx = elElfDesc->SymEx; if( CurrentSymEx) { while( CurrentSymEx->next != NULL) { FwdSymEx = CurrentSymEx; CurrentSymEx = CurrentSymEx->next; free( FwdSymEx); } elElfDesc->SymEx = NULL; } /*-----------------------------------------*/ /* if( *sym_table) { // Deallocated by the application here and so commented out free( *sym_table); }*/ elElfDesc->SymExTarget = 0xFFFFFFFF; } /*------------------------------------------------------ Read ELSymEx of the index specified from the list. -----------------------------------------------------*/ ELSymEx* ELi_GetSymExfromList( ELSymEx* SymExStart, u32 index) { u32 i; ELSymEx* SymEx; SymEx = SymExStart; for( i=0; inext); if( SymEx == NULL) { break; } } return SymEx; } /*------------------------------------------------------ Read ELShdrx of the index specified from the list. -----------------------------------------------------*/ ELShdrEx* ELi_GetShdrExfromList( ELShdrEx* ShdrExStart, u32 index) { u32 i; ELShdrEx* ShdrEx; ShdrEx = ShdrExStart; for( i=0; inext); if( ShdrEx == NULL) { break; } } return ShdrEx; } /*------------------------------------------------------ Determine whether the section for the specified index is debug information - Sections whose section name begins with .debug. - Section, such as .rel.debug - section, where the sh_info indicates the debug information section number -----------------------------------------------------*/ BOOL ELi_ShdrIsDebug( ELHandle* ElfHandle, u32 index) { Elf32_Shdr TmpShdr; char shstr[6]; /*-- Get six characters of character string for section name --*/ ELi_GetShdr( ElfHandle, index, &TmpShdr); ELi_GetStrAdr( ElfHandle, ElfHandle->CurrentEhdr.e_shstrndx, TmpShdr.sh_name, shstr, 6); /*-------------------------------------*/ if( strncmp( shstr, ".debug", 6) == 0) { /*When debugging section*/ return TRUE; }else{ /*When relocated section relates to the debugging section*/ if( (TmpShdr.sh_type == SHT_REL) || (TmpShdr.sh_type == SHT_RELA)) { if( ELi_ShdrIsDebug( ElfHandle, TmpShdr.sh_info) == TRUE) { return TRUE; } } } return FALSE; } /*------------------------------------------------------ Checks the ElfHandle SymEx table, and determines whether the code in the specified offset of the specified index is ARM or THUMB. (Preset ElfHandle->SymShdr and ElfHandle->SymEx.) sh_index: Section index to be checked offset: Offset in section to check -----------------------------------------------------*/ u32 ELi_CodeIsThumb( ELHandle* ElfHandle, u16 sh_index, u32 offset) { u32 i; u32 thumb_flag; Elf32_Shdr* SymShdr; char str_adr[3]; ELSymEx* CurrentSymEx; /*Get symbol section header and SymEx list*/ SymShdr = &(ElfHandle->SymShdr); CurrentSymEx = ElfHandle->SymEx; i = 0; thumb_flag = 0; while( CurrentSymEx != NULL) { if( CurrentSymEx->Sym.st_shndx == sh_index) { ELi_GetStrAdr( ElfHandle, SymShdr->sh_link, CurrentSymEx->Sym.st_name, str_adr, 3); if( strncmp( str_adr, "$a\0", strlen("$a\0")) == 0) { thumb_flag = 0; }else if( strncmp( str_adr, "$t\0", strlen("$t\0")) == 0) { thumb_flag = 1; } if( CurrentSymEx->Sym.st_value > offset) { break; } } CurrentSymEx = CurrentSymEx->next; i++; } return thumb_flag; } /*--------------------------------------------------------- Initialize unresolved information entries --------------------------------------------------------*/ void ELi_UnresolvedInfoInit( ELUnresolvedEntry* UnresolvedInfo) { UnresolvedInfo->sym_str = NULL; UnresolvedInfo->r_type = 0; UnresolvedInfo->S_ = 0; UnresolvedInfo->A_ = 0; UnresolvedInfo->P_ = 0; UnresolvedInfo->T_ = 0; UnresolvedInfo->remove_flag = 0; } /*------------------------------------------------------ Delete entry from the unresolved information table -----------------------------------------------------*/ BOOL ELi_RemoveUnresolvedEntry( ELUnresolvedEntry* UnrEnt) { ELUnresolvedEntry DmyUnrEnt; ELUnresolvedEntry* CurrentUnrEnt; if( UnrEnt == NULL) { return FALSE; } DmyUnrEnt.next = ELUnrEntStart; CurrentUnrEnt = &DmyUnrEnt; while( CurrentUnrEnt->next != UnrEnt) { if( CurrentUnrEnt->next == NULL) { return FALSE; }else{ CurrentUnrEnt = (ELUnresolvedEntry*)(CurrentUnrEnt->next); } } CurrentUnrEnt->next = UnrEnt->next; free( UnrEnt->sym_str); free( UnrEnt); ELUnrEntStart = DmyUnrEnt.next; return TRUE; } /*--------------------------------------------------------- Add entry to the unresolved information table --------------------------------------------------------*/ void ELi_AddUnresolvedEntry( ELUnresolvedEntry* UnrEnt) { ELUnresolvedEntry DmyUnrEnt; ELUnresolvedEntry* CurrentUnrEnt; if( !ELUnrEntStart) { ELUnrEntStart = UnrEnt; }else{ DmyUnrEnt.next = ELUnrEntStart; CurrentUnrEnt = &DmyUnrEnt; while( CurrentUnrEnt->next != NULL) { CurrentUnrEnt = CurrentUnrEnt->next; } CurrentUnrEnt->next = (void*)UnrEnt; } UnrEnt->next = NULL; } /*------------------------------------------------------ Search for entry corresponding to specified string in the unresolved information table -----------------------------------------------------*/ ELUnresolvedEntry* ELi_GetUnresolvedEntry( char* ent_name) { ELUnresolvedEntry* CurrentUnrEnt; CurrentUnrEnt = ELUnrEntStart; if( CurrentUnrEnt == NULL) { return NULL; } while( 1) { if( (strcmp( CurrentUnrEnt->sym_str, ent_name) == 0)&& (CurrentUnrEnt->remove_flag == 0)) { break; } CurrentUnrEnt = (ELUnresolvedEntry*)CurrentUnrEnt->next; if( CurrentUnrEnt == NULL) { break; } } return CurrentUnrEnt; }