]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/services/objloader/v2_0/src/objelf.c
Initial revision
[karo-tx-redboot.git] / packages / services / objloader / v2_0 / src / objelf.c
1 /* =================================================================
2  *
3  *      objelf.c
4  *
5  *      Relocation routine for eCos loader.
6  *
7  * ================================================================= 
8  * ####ECOSGPLCOPYRIGHTBEGIN####
9  * -------------------------------------------
10  * This file is part of eCos, the Embedded Configurable Operating
11  * System.
12  * Copyright (C) 2005 eCosCentric Ltd.
13  * 
14  * eCos is free software; you can redistribute it and/or modify it
15  * under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 or (at your option)
17  * any later version.
18  * 
19  * eCos is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with eCos; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27  * 
28  * As a special exception, if other files instantiate templates or
29  * use macros or inline functions from this file, or you compile this
30  * file and link it with other works to produce a work based on this
31  * file, this file does not by itself cause the resulting work to be
32  * covered by the GNU General Public License. However the source code
33  * for this file must still be made available in accordance with
34  * section (3) of the GNU General Public License.
35  * 
36  * This exception does not invalidate any other reasons why a work
37  * based on this file might be covered by the GNU General Public
38  * License.
39  *
40  * -------------------------------------------
41  * ####ECOSGPLCOPYRIGHTEND####
42  * =================================================================
43  * #####DESCRIPTIONBEGIN####
44  * 
45  *  Author(s):    atonizzo@lycos.com
46  *  Contributors: nickg@ecoscentric.com
47  *  Date:         2005-05-13
48  *  Purpose:      
49  *  Description:  
50  *               
51  * ####DESCRIPTIONEND####
52  * 
53  * =================================================================
54  */
55
56 #include <cyg/infra/diag.h>     // For diagnostic printing.
57 #include <pkgconf/io_fileio.h>
58 #include <cyg/hal/hal_tables.h>
59 #include <stdio.h>
60
61 #include <pkgconf/objloader.h>
62 #include <cyg/objloader/elf.h>
63 #include <cyg/objloader/objelf.h>
64
65 CYG_HAL_TABLE_BEGIN( cyg_ldr_table, ldr_table );
66 CYG_HAL_TABLE_END( cyg_ldr_table_end, ldr_table );
67
68 __externC cyg_ldr_table_entry cyg_ldr_table[];
69 __externC cyg_ldr_table_entry cyg_ldr_table_end[];
70
71 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0
72 void 
73 cyg_ldr_print_section_data( PELF_OBJECT p )
74 {
75     cyg_int32  i;
76     cyg_uint8  strname[32];
77     cyg_uint8  *p_strtab = (cyg_uint8*)p->sections[p->p_elfhdr->e_shstrndx];
78     
79     diag_printf( "\n\nSection Headers:\n" ); 
80     diag_printf( "[Nr]  Name                  Addr    Offset    Size     Info\n" );
81     for ( i = 0; i < p->p_elfhdr->e_shnum; i++ )
82     {
83         sprintf( strname, "%s", p_strtab + p->p_sechdr[i].sh_name );
84         while ( strlen( strname ) < 20 )
85             strcat( strname, " " );
86         diag_printf( "[%02d] %s %08X %08X %08X %08X\n",  
87                      i, 
88                      strname,
89                      p->p_sechdr[i].sh_addr,
90                      p->p_sechdr[i].sh_offset,
91                      p->p_sechdr[i].sh_size,
92                      p->p_sechdr[i].sh_info );
93     }                 
94     diag_printf( "\n" ); 
95 }
96
97 void 
98 cyg_ldr_print_symbol_names( PELF_OBJECT p )
99 {
100     cyg_int32  i, symtab_entries;
101     Elf32_Sym *p_symtab = (Elf32_Sym*)p->sections[p->hdrndx_symtab];
102     cyg_uint8 *p_strtab = (cyg_uint8*)p->sections[p->hdrndx_strtab];
103     cyg_uint8  strname[32];
104
105     // Total number of entries in the symbol table.
106     symtab_entries = p->p_sechdr[p->hdrndx_symtab].sh_size / 
107                                 p->p_sechdr[p->hdrndx_symtab].sh_entsize;
108     diag_printf( "Num  Value     Size Ndx   Name\n" ); 
109     for ( i = 1; i < symtab_entries; i++ )
110     {
111         sprintf( strname, "%d", i );
112         while ( strlen( strname ) < 5 )
113             strcat( strname, " " );
114         diag_printf( strname );         
115         
116         sprintf( strname, 
117                  "%08X  %d", 
118                  p_symtab[i].st_value, 
119                  p_symtab[i].st_size );
120         while ( strlen( strname ) < 15 )
121             strcat( strname, " " );
122         diag_printf( strname );         
123         
124         sprintf( strname, "%d", p_symtab[i].st_shndx );
125         while ( strlen( strname ) < 6 )
126             strcat( strname, " " );
127         diag_printf( strname );         
128         
129         strncpy( strname, 
130                  p_strtab + p_symtab[i].st_name, 
131                  sizeof( strname ) - 1 );
132         strname[strlen( p_strtab + p_symtab[i].st_name )] = '\0';
133         diag_printf( strname );         
134         diag_printf( "\n" );         
135     }
136 }
137
138 void 
139 cyg_ldr_print_rel_names( PELF_OBJECT p )
140 {
141     cyg_int32     i, j, r_entries, sym_index;
142     Elf32_Sym *p_symtab = (Elf32_Sym*)p->sections[p->hdrndx_symtab];
143     cyg_uint8 *p_strtab = (cyg_uint8*)p->sections[p->hdrndx_strtab];
144     cyg_uint8 *p_shstrtab = (cyg_uint8*)p->sections[p->p_elfhdr->e_shstrndx];
145 #if ELF_ARCH_RELTYPE == Elf_Rela        
146     Elf32_Rela*   p_rela;
147 #else
148     Elf32_Rel*    p_rel;
149 #endif
150     cyg_uint8  strname[32];
151
152     for ( i = 1; i < p->p_elfhdr->e_shnum; i++ )
153     {
154         if ( ( p->p_sechdr[i].sh_type == SHT_REL ) ||
155                                   ( p->p_sechdr[i].sh_type == SHT_RELA ) )
156         {                                  
157             // Calculate the total number of entries in the .rela section.
158             r_entries = p->p_sechdr[i].sh_size / p->p_sechdr[i].sh_entsize;
159
160             diag_printf( "\n\nSymbols at: %s\n\n", 
161                          p_shstrtab + p->p_sechdr[i].sh_name );
162 #if ELF_ARCH_RELTYPE == Elf_Rela        
163             p_rela = (Elf32_Rela*)cyg_ldr_load_elf_section( p, i );
164             printf( "Offset    Info      Name [+ Addend]\n" );
165 #else
166             p_rel = (Elf32_Rel*)cyg_ldr_load_elf_section( p, i );
167             printf( "Offset    Info     Name\n" );
168 #endif
169
170             for ( j = 0; j < r_entries; j++ )
171             {
172                 sprintf( strname, 
173                          "%08X  %08X  ", 
174 #if ELF_ARCH_RELTYPE == Elf_Rela        
175                          p_rela[j].r_offset,
176                          p_rela[j].r_info 
177 #else
178                          p_rel[j].r_offset,
179                          p_rel[j].r_info 
180 #endif
181                          );
182
183                 diag_printf( strname );         
184
185 #if ELF_ARCH_RELTYPE == Elf_Rela        
186                 cyg_uint8 sym_type = ELF32_R_SYM( p_rela[j].r_info );
187 #else
188                 cyg_uint8 sym_type = ELF32_R_SYM( p_rel[j].r_info );
189 #endif
190                 if ( strlen ( p_strtab + p_symtab[sym_type].st_name ) > 0 )
191                     diag_printf( p_strtab + p_symtab[sym_type].st_name );         
192                 else 
193                 {   
194                     // If the symbol name is not available, then print
195                     //  the name of the section.
196                     sym_index = p_symtab[sym_type].st_shndx;                    
197                     diag_printf( p_shstrtab + p->p_sechdr[sym_index].sh_name );         
198                 }    
199 #if ELF_ARCH_RELTYPE == Elf_Rela        
200                 if ( p_rela[j].r_addend != 0 )
201                     diag_printf( " + %08X", p_rela[j].r_addend );
202 #endif
203                 diag_printf( "\n" );         
204             }            
205             // After all the printing is done, the relocation table can 
206             //  be dumped.
207             cyg_ldr_delete_elf_section( p, i );
208         } 
209     }    
210 }
211 #endif // DEBUG_PRINT
212
213 static void
214 *cyg_ldr_local_address( PELF_OBJECT p, cyg_uint32 sym_index )
215 {
216     cyg_uint32 data_sec, addr;
217     Elf32_Sym *p_symtab;
218
219     p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab );
220     
221     // Find out the section number in which the data for this symbol is 
222     //  located.
223     data_sec = p_symtab[sym_index].st_shndx;    
224
225     // From the section number we get the start of the memory area in 
226     //  memory.
227     addr = (cyg_uint32)cyg_ldr_section_address( p, data_sec );
228
229     // And now return the address of the data.
230     return (void*)( addr + p_symtab[sym_index].st_value);
231 }    
232
233 void
234 *cyg_ldr_external_address( PELF_OBJECT p, cyg_uint32 sym_index )
235 {
236     cyg_uint8*    tmp2;
237     Elf32_Sym *p_symtab;
238     cyg_uint8 *p_strtab;
239     cyg_ldr_table_entry *entry = cyg_ldr_table;
240   
241   
242     p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab );
243     p_strtab = (cyg_uint8*)cyg_ldr_section_address( p, p->hdrndx_strtab );
244   
245     // This is the name of the external reference to search.
246     tmp2 = p_strtab + p_symtab[sym_index].st_name;
247     while ( entry != cyg_ldr_table_end )
248     {
249         if ( !strcmp( (const char*)tmp2, entry->symbol_name  ) )
250             return entry->handler;
251         entry++;
252     }
253
254     // Symbol not found.
255     return 0;
256 }
257
258 // input:
259 // p          : Pointer to the elf file object
260 // sym_index  : Index of the symbol to be searched (in the SYMTAB)
261 //
262 // out:
263 // 0          : Symbol not found
264 // Other      : Address of the symbol in absolute memory.
265 void 
266 *cyg_ldr_symbol_address( PELF_OBJECT p, cyg_uint32 sym_index )
267 {
268     cyg_uint32 addr;
269     cyg_uint8  sym_info;
270     Elf32_Sym *p_symtab;
271
272     p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab );
273     sym_info = p_symtab[sym_index].st_info;
274     
275     switch ( ELF32_ST_TYPE( sym_info ) )
276     {
277     case STT_NOTYPE:
278     case STT_FUNC:
279     case STT_OBJECT:
280         switch ( ELF32_ST_BIND( sym_info ) )
281         {
282         case STB_LOCAL:
283         case STB_GLOBAL:
284             if ( p_symtab[sym_index].st_shndx == SHN_UNDEF ) 
285                 return cyg_ldr_external_address( p, sym_index );
286             else
287                 return cyg_ldr_local_address( p, sym_index );
288         case STB_WEAK:
289             addr = (cyg_uint32)cyg_ldr_external_address( p, sym_index );
290             if ( addr != 0 )
291                 return (void*)addr;
292             else    
293                 return cyg_ldr_local_address( p, sym_index );
294         default:
295             return 0;
296         }
297         break;
298     case STT_SECTION:
299         // Return the starting address of a section, given its index.
300         return (void*)cyg_ldr_section_address( p, 
301                                                p_symtab[sym_index].st_shndx );
302     default:
303         return 0;
304     }
305 }
306
307 // Loads the relocation information, relocates, and dumps the relocation
308 //  information once the process is complete.
309 cyg_int32 
310 cyg_ldr_relocate_section( PELF_OBJECT p, cyg_uint32 r_shndx )
311 {
312     cyg_int32   i, rc;
313     cyg_uint32  r_entries, r_target_shndx, r_target_addr;
314     cyg_uint32  sym_value, sym_index;
315     Elf32_Addr  r_offset;
316     Elf32_Word  r_type;
317     Elf32_Sword r_addend;
318 #if ELF_ARCH_RELTYPE == Elf_Rela        
319     Elf32_Rela* p_rela = (Elf32_Rela*)cyg_ldr_load_elf_section( p, r_shndx );
320 #else
321     Elf32_Rel*  p_rel = (Elf32_Rel*)cyg_ldr_load_elf_section( p, r_shndx );
322 #endif
323
324 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0
325     Elf32_Sym *p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, 
326                                                            p->hdrndx_symtab );
327     cyg_uint8 *p_strtab = (cyg_uint8*)cyg_ldr_section_address( p, 
328                                                            p->hdrndx_strtab );
329     cyg_uint8 *p_shstrtab = (cyg_uint8*)cyg_ldr_section_address( p, 
330                                                      p->p_elfhdr->e_shstrndx );
331 #endif
332
333     // Now we can get the address of the contents of the section to modify.
334     r_target_shndx = p->p_sechdr[r_shndx].sh_info;
335     r_target_addr  = (cyg_uint32)cyg_ldr_section_address( p, r_target_shndx );
336
337 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0
338     diag_printf( "Relocating section \"%s\"\n",
339             p_shstrtab + p->p_sechdr[r_target_shndx].sh_name );
340 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 1
341     diag_printf( "Ndx   Type   Offset    Name\"\n" );
342 #endif
343 #endif
344
345     // Perform relocatation for each of the members of this table.
346     r_entries = p->p_sechdr[r_shndx].sh_size / p->p_sechdr[r_shndx].sh_entsize;
347     for ( i = 0; i < r_entries; i++ )
348     {
349 #if ELF_ARCH_RELTYPE == Elf_Rela        
350         r_offset  = p_rela[i].r_offset; 
351         r_type    = ELF32_R_TYPE( p_rela[i].r_info ); 
352         sym_index = ELF32_R_SYM( p_rela[i].r_info );
353         r_addend  = p_rela[i].r_addend; 
354 #else
355         r_offset  = p_rel[i].r_offset; 
356         r_type    = ELF32_R_TYPE( p_rel[i].r_info ); 
357         sym_index = ELF32_R_SYM( p_rel[i].r_info );
358         r_addend  = 0; 
359 #endif
360
361         sym_value = (cyg_uint32)cyg_ldr_symbol_address( p, sym_index );
362         if ( sym_value == 0 )
363         {
364 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0
365             diag_printf( "Unknown symbol value: %s Index: %d\n",
366                          p_strtab + p_symtab[sym_index].st_name,
367                          sym_index );
368 #endif
369             return -1;
370         }    
371         
372         // This is architecture dependent, and deals with whether we have
373         //  '.rel' or '.rela' sections.
374 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 1
375         diag_printf( "%04X  %04X  %08X  ",
376                      sym_index,
377                      r_type,
378                      r_offset );
379         if ( strlen ( p_strtab + p_symtab[sym_index].st_name ) > 0 )
380             diag_printf( p_strtab + p_symtab[sym_index].st_name );         
381         else 
382         {   
383             // If the symbol name is not available, then print
384             //  the name of the section.
385             cyg_uint32 sec_ndx = p_symtab[sym_index].st_shndx;                    
386             diag_printf( p_shstrtab + p->p_sechdr[sec_ndx].sh_name );         
387         }    
388         diag_printf( "\n" );         
389 #endif
390         rc = cyg_ldr_relocate( r_type,
391                                r_target_addr + r_offset, 
392                                sym_value + r_addend );
393         if ( rc != 0 )
394         {
395 #if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0
396             diag_printf( "Relocation error: Cannot find symbol: %s\n",
397                       p_strtab + p_symtab[sym_index].st_name );
398 #endif
399             return -1;
400         }    
401     }
402
403     // After the relocation is done, the relocation table can be dumped.
404     cyg_ldr_delete_elf_section( p, r_shndx );
405     return 0;
406 }
407