|
1 /* |
|
2 * Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include <string.h> |
|
21 #include <stdlib.h> |
|
22 #include <e32std.h> |
|
23 #include <elfdefs.h> |
|
24 #include "elfdll.h" |
|
25 #include "elffile.h" |
|
26 #include <h_utl.h> |
|
27 #include <e32ldr.h> |
|
28 |
|
29 ELFFile::ELFDllData::ELFDllData(ELFFile * f) |
|
30 : |
|
31 iElfFile(f), |
|
32 |
|
33 iDynStrTab(0), |
|
34 iDynStrTabSize(0), |
|
35 iDynSymTab(0), |
|
36 |
|
37 iSymSize(0), |
|
38 iRela(0), |
|
39 iRelaSz(0), |
|
40 iRelaEnt(0), |
|
41 |
|
42 iRel(0), |
|
43 iRelSz(0), |
|
44 iRelEnt(0), |
|
45 |
|
46 iHashTable(0), |
|
47 |
|
48 iNamedExportSymbolHead(0), |
|
49 iNamedExportCount(0), |
|
50 |
|
51 iSymStringTableSize(0), |
|
52 iStringNameOffset(0), |
|
53 |
|
54 iDepRecords(0), |
|
55 iDepRecordsTail(0), |
|
56 |
|
57 iNeededDllNames(0), |
|
58 iNeededDllNamesTail(0), |
|
59 |
|
60 iOrdZeroRec(0), |
|
61 |
|
62 iNamedLookupEnabled(0), |
|
63 |
|
64 iDllHead(0), |
|
65 iDllTail(0), |
|
66 |
|
67 iNumberOfImports(0), |
|
68 iNumberOfExports(0), |
|
69 iNumberOfImportDlls(0), |
|
70 |
|
71 iStringTableSize(0), |
|
72 |
|
73 iNumberOfRelocs(0), |
|
74 iNumberOfCodeRelocs(0), |
|
75 iNumberOfDataRelocs(0) |
|
76 { |
|
77 } |
|
78 |
|
79 ELFFile::ELFDllData::~ELFDllData() |
|
80 { |
|
81 delete iOrdZeroRec; |
|
82 delete iDepRecords; |
|
83 delete iNeededDllNames; |
|
84 } |
|
85 |
|
86 TBool ELFFile::ELFDllData::Init() |
|
87 { |
|
88 // process imported symbols |
|
89 // There will be at least one relocation (assumed to be Elf32_Rel) for each such symbol. |
|
90 // S iterate over relocations looking for DLL symbols and add them to the record of |
|
91 // of import info. |
|
92 TInt nrelocs = iRelSz/iRelEnt; |
|
93 TInt SrcSegIdx = -1; |
|
94 TInt errors = 0; |
|
95 |
|
96 for (TInt idx = 0; idx < nrelocs; idx++) |
|
97 { |
|
98 Elf32_Rel * rel = &iRel[idx]; |
|
99 TUint relType = ELF32_R_TYPE(rel->r_info); |
|
100 |
|
101 if (relType == R_ARM_ABS32) |
|
102 { |
|
103 TInt symIdx = ELF32_R_SYM(rel->r_info); |
|
104 Elf32_Sym * sym = &iDynSymTab[symIdx]; |
|
105 DllSymbol * dllSym = DllSymbolP(sym); |
|
106 if (dllSym) |
|
107 { |
|
108 dllSym->iRel = rel; |
|
109 dllSym->iSegment = iElfFile->GetSegment(SrcSegIdx); |
|
110 if (!AddSymbol(dllSym)) return EFalse; |
|
111 } |
|
112 else errors++; |
|
113 } |
|
114 else if (relType == R_ARM_RABS32) |
|
115 { |
|
116 iNumberOfRelocs++; |
|
117 if (iElfFile->CodeSegmentP(SrcSegIdx)) iNumberOfCodeRelocs++; |
|
118 else iNumberOfDataRelocs++; |
|
119 } |
|
120 else if (relType == R_ARM_RBASE) |
|
121 { |
|
122 SrcSegIdx = ELF32_R_SYM(rel->r_info); |
|
123 if (SrcSegIdx) SrcSegIdx--; |
|
124 } |
|
125 else |
|
126 { |
|
127 // Gives error with all other Relocation types.. |
|
128 TInt symIdx = ELF32_R_SYM(rel->r_info); |
|
129 Elf32_Sym * s = &iDynSymTab[symIdx]; |
|
130 char * symName = ELFADDR(char,iDynStrTab,s->st_name); |
|
131 Print(EPeError, "Unresolved symbol: %s\n", symName); |
|
132 errors++; |
|
133 } |
|
134 } |
|
135 // Set up export info |
|
136 if (InitExportInfo()) |
|
137 { |
|
138 TText * sym = (TText *)"_E32Startup"; |
|
139 // If _E32Startup is defined then this is not a DLL |
|
140 iImageIsDll = !iElfFile->SymbolPresent(sym); |
|
141 } |
|
142 if (errors > 0) return EFalse; |
|
143 return ETrue; |
|
144 } |
|
145 |
|
146 TBool ELFFile::ELFDllData::ParseDllSymbol(Elf32_Sym * s, char *& dll, TUint& len, TInt& ord) |
|
147 { |
|
148 char * sym = ELFADDR(char,iDynStrTab,s->st_name); |
|
149 if (!strncmp(sym, DLLSYMPREFIX, strlen(DLLSYMPREFIX))) |
|
150 { |
|
151 dll = sym + strlen(DLLSYMPREFIX); |
|
152 TUint lim = strlen(dll); |
|
153 TUint index = strcspn(dll, DLLSYMPREFIX0); |
|
154 if ((index + strlen(DLLSYMSUFFIX)) < lim) |
|
155 { |
|
156 len = index; |
|
157 char * dllSuffix = dll+index; |
|
158 char * match = DLLSYMSUFFIX; |
|
159 int suflen = strlen(DLLSYMSUFFIX); |
|
160 if (!strncmp(dllSuffix, match, suflen)) |
|
161 { |
|
162 char * ordString = dll+index+suflen; |
|
163 char * final; |
|
164 TUint X = strtoul(ordString, &final, ORDBASE); |
|
165 if (ordString != final) |
|
166 { |
|
167 ord = (TInt)X; |
|
168 return ETrue; |
|
169 } |
|
170 |
|
171 } |
|
172 } |
|
173 } |
|
174 dll = 0; |
|
175 len = 0; |
|
176 ord = -1; |
|
177 return EFalse; |
|
178 } |
|
179 |
|
180 ELFFile::ELFDllData::DllSymbol * ELFFile::ELFDllData::DllSymbolP(Elf32_Sym * s) |
|
181 { |
|
182 char * dllName; |
|
183 TUint nameLen; |
|
184 TInt symOrd; |
|
185 if (ParseDllSymbol(s, dllName, nameLen, symOrd)) |
|
186 { |
|
187 DllSymbol * ds = new DllSymbol(dllName, nameLen, symOrd); |
|
188 if (ds) return ds; |
|
189 Print(EPeError, "Out of memory.\n"); |
|
190 return NULL; |
|
191 } |
|
192 // If we get here its not a valid 'dll symbol' and so it is an unresolved symbol |
|
193 char * sym = ELFADDR(char,iDynStrTab,s->st_name); |
|
194 Print(EPeError, "Unresolved symbol: %s\n", sym); |
|
195 return NULL; |
|
196 } |
|
197 |
|
198 TBool ELFFile::ELFDllData::AddSymbol(ELFFile::ELFDllData::DllSymbol * s) |
|
199 { |
|
200 DllRec * aDll = NULL; |
|
201 |
|
202 for (DllRec * r = iDllHead; r != NULL; r = r->iNext) |
|
203 { |
|
204 if (!strncmp(s->iDll, r->iName, s->iLen)) |
|
205 { |
|
206 aDll = r; |
|
207 break; |
|
208 } |
|
209 } |
|
210 if (aDll) |
|
211 { |
|
212 iNumberOfImports++; |
|
213 aDll->AddSymbol(s); |
|
214 return ETrue; |
|
215 } |
|
216 else |
|
217 { |
|
218 aDll = new DllRec(s->iDll, s->iLen, s); |
|
219 if (aDll) |
|
220 { |
|
221 if (!iDllHead) |
|
222 { |
|
223 iDllHead = iDllTail = aDll; |
|
224 } |
|
225 else |
|
226 { |
|
227 iDllTail->iNext = aDll; |
|
228 iDllTail = aDll; |
|
229 } |
|
230 iStringTableSize += (s->iLen + 1); |
|
231 iNumberOfImportDlls++; |
|
232 iNumberOfImports++; |
|
233 return ETrue; |
|
234 } |
|
235 else |
|
236 { |
|
237 Print(EPeError, "Out of memory.\n"); |
|
238 return EFalse; |
|
239 } |
|
240 } |
|
241 } |
|
242 |
|
243 void ELFFile::ELFDllData::DllRec::AddSymbol(ELFFile::ELFDllData::DllSymbol * s) |
|
244 { |
|
245 nImports++; |
|
246 iTail->iNext = s; |
|
247 iTail = s; |
|
248 } |
|
249 |
|
250 static unsigned long elf_hash(const unsigned char *name) |
|
251 { |
|
252 unsigned long h, g; |
|
253 for (h = 0; *name != 0; ++name) |
|
254 { |
|
255 h = (h << 4) + *name; |
|
256 g = h & 0xf0000000; |
|
257 if (g != 0) h ^= g >> 24; |
|
258 h &= ~g; |
|
259 } |
|
260 return h; |
|
261 } |
|
262 |
|
263 Elf32_Word ELFFile::ELFDllData::FindSymbolIndex(TText * s) |
|
264 { |
|
265 TUint h = elf_hash(s); |
|
266 TUint nb = iHashTable[0].nBuckets; |
|
267 TUint probe = h%nb; |
|
268 Elf32_Sword * bucket = ELFADDR(Elf32_Sword, iHashTable, sizeof(Elf32_HashTable)); |
|
269 Elf32_Sword * chain = ELFADDR(Elf32_Sword, bucket, nb * sizeof(Elf32_Sword)); |
|
270 Elf32_Sword idx = bucket[probe]; |
|
271 |
|
272 do |
|
273 { |
|
274 if (!strcmp(ELFADDR(char, iDynStrTab, iDynSymTab[idx].st_name), (char *)s)) return idx; |
|
275 idx = chain[idx]; |
|
276 } while (idx > 0); |
|
277 if (idx == 0) idx = -1; |
|
278 return idx; |
|
279 } |
|
280 |
|
281 TBool ELFFile::ELFDllData::InitExportInfo() |
|
282 { |
|
283 memset(&iSymInfoHdr, 0, sizeof(iSymInfoHdr)); |
|
284 TText * exp = (TText *)EXPORTTABLENAME; |
|
285 if ( int(iExportTableSymIdx = FindSymbolIndex(exp)) != -1 ) |
|
286 { |
|
287 TText * exps = (TText *)EXPORTTABLESIZENAME; |
|
288 iExportTableSizeSymIdx = FindSymbolIndex(exps); |
|
289 //TUint offset = iDynSymTab[iExportTableSizeSymIdx].st_value - (TUint)code; |
|
290 Elf32_Word * pNumberOfExports = iElfFile->CodePtrFromAddr(iDynSymTab[iExportTableSizeSymIdx].st_value); |
|
291 iNumberOfExports = * pNumberOfExports; |
|
292 iImageIsDll = ETrue; |
|
293 return ETrue; |
|
294 } |
|
295 else iImageIsDll = EFalse; |
|
296 return EFalse; |
|
297 } |
|
298 |
|
299 TInt ELFFile::ELFDllData::NumberOfImports(void) |
|
300 { |
|
301 return iNumberOfImports; |
|
302 } |
|
303 |
|
304 TInt ELFFile::ELFDllData::NumberOfExports(void) |
|
305 { |
|
306 return iNumberOfExports; |
|
307 } |
|
308 |
|
309 TInt ELFFile::ELFDllData::NumberOfImportDlls(void) |
|
310 { |
|
311 return iNumberOfImportDlls; |
|
312 } |
|
313 |
|
314 TInt ELFFile::ELFDllData::NumberOfRelocs() |
|
315 { |
|
316 return iNumberOfRelocs; |
|
317 } |
|
318 |
|
319 char * ELFFile::ELFDllData::CreateImportSection(TInt &aSize) |
|
320 { |
|
321 if (!iNumberOfImports) |
|
322 { |
|
323 aSize = 0; |
|
324 return 0; |
|
325 } |
|
326 |
|
327 TInt byteSize = sizeof(E32ImportSection) + |
|
328 (sizeof(E32ImportBlock) * iNumberOfImportDlls) + |
|
329 (sizeof(TUint) * iNumberOfImports) + |
|
330 iStringTableSize; |
|
331 if(iNamedLookupEnabled) |
|
332 { |
|
333 // 0th ordinal of each DLL imported from. |
|
334 byteSize += (sizeof(TUint) * iNumberOfImportDlls); |
|
335 } |
|
336 char * newSection = new char[byteSize]; |
|
337 |
|
338 if (!newSection) |
|
339 { |
|
340 Print(EPeError, "Failed to allocate new import section.\n"); |
|
341 aSize = 0; |
|
342 return 0; |
|
343 } |
|
344 |
|
345 ((E32ImportSection *)newSection)->iSize = byteSize; |
|
346 |
|
347 // used to point to current ImportBlock |
|
348 E32ImportBlock * bp = ELFADDR(E32ImportBlock, newSection, sizeof(E32ImportSection)); |
|
349 // used to point to current import relocation entry |
|
350 TUint * rp; |
|
351 // used to point to current location in string table |
|
352 char * sp = ELFADDR(char, newSection, (byteSize - iStringTableSize)); |
|
353 OrdZeroRecord *aDep = iDepRecords; |
|
354 |
|
355 for (DllRec * dll = iDllHead; dll != NULL ; dll = dll->iNext, bp = (E32ImportBlock *)rp ) |
|
356 { |
|
357 // set up the offset from E32ImportBlock.iOffsetOfDllName to the |
|
358 // corresponding string table location |
|
359 bp->iOffsetOfDllName = (sp - (char *)newSection); |
|
360 bp->iNumberOfImports = dll->nImports; |
|
361 if(iNamedLookupEnabled) |
|
362 { |
|
363 bp->iNumberOfImports++; |
|
364 } |
|
365 |
|
366 // copy the DLL name to the string table |
|
367 memcpy(sp , dll->iName, dll->iLen); |
|
368 sp[dll->iLen] = 0; |
|
369 sp = sp + dll->iLen + 1; |
|
370 |
|
371 // sort out the import 'relocs' |
|
372 rp = ELFADDR(TUint, bp, sizeof(E32ImportBlock)); |
|
373 |
|
374 for (DllSymbol * sym = dll->iHead; sym != NULL; sym = sym->iNext, rp++) |
|
375 { |
|
376 Elf32_Phdr * segment = sym->iSegment; |
|
377 Elf32_Addr segBase = segment->p_vaddr; |
|
378 |
|
379 // sanity check: segment should be the code segment |
|
380 if (!iElfFile->CodeSegmentP(segment)) |
|
381 { |
|
382 Print(EPeError, "Import relocation does not refer to code segment.\n"); |
|
383 aSize = 0; |
|
384 return 0; |
|
385 } |
|
386 |
|
387 // This field is misnamed because it is actually given as a virtual address in |
|
388 // dynamic relocations |
|
389 Elf32_Addr dynOffset = sym->iRel->r_offset; |
|
390 //So this is the 'real' offset of the reloc in the segment in which it occurs |
|
391 Elf32_Addr segOffset = dynOffset - segBase; |
|
392 TUint * relocAddr = ELFADDR(TUint, iElfFile->ELFFileBase(), (segment->p_offset + segOffset)); |
|
393 // The only non-zero reloc vals we expect are for vtables. |
|
394 // We store there reloc offset in the top 16 bits of the 'reloc info'. |
|
395 // NB the ELF reloc values should only ever be multiples of 4. So we could optimize here, |
|
396 // but we won't. |
|
397 TUint relocVal = *relocAddr; |
|
398 TUint importOrdinal = sym->iOrd; |
|
399 if (relocVal > 0xFFFF) |
|
400 Print(EPeError, "ELF relocation exceeds E32Image limit of 64K.\n"); |
|
401 if (importOrdinal > 0xFFFF) |
|
402 Print(EPeError, "Import ordinal exceeds E32Image limit of 64K.\n"); |
|
403 |
|
404 *rp = segOffset; |
|
405 |
|
406 // eek !! surgery on the code segment.... |
|
407 *relocAddr = (relocVal<<16) | importOrdinal; |
|
408 } |
|
409 |
|
410 if(iNamedLookupEnabled) |
|
411 { |
|
412 aDep = FindDependency(dll->iName, dll->iLen); |
|
413 if( aDep ) |
|
414 { |
|
415 *rp = aDep->iOffset; |
|
416 rp++; |
|
417 } |
|
418 } |
|
419 } |
|
420 |
|
421 aSize = byteSize; |
|
422 return newSection; |
|
423 } |
|
424 |
|
425 TUint ELFFile::ELFDllData::GetExportTableOffset(void) |
|
426 { |
|
427 Elf32_Sym * et = &iDynSymTab[iExportTableSymIdx]; |
|
428 Elf32_Phdr * segment = iElfFile->GetSegment(et->st_shndx - 1); |
|
429 |
|
430 return et->st_value - segment->p_vaddr; |
|
431 } |
|
432 |
|
433 TBool ELFFile::ELFDllData::GetRelocs(Elf32_Rel **aCodeRelocs, Elf32_Rel **aDataRelocs) |
|
434 // |
|
435 // load the relocs from the reloc section into relocation and relocsection arrays |
|
436 // |
|
437 { |
|
438 TInt nrelocs = iRelSz/iRelEnt; |
|
439 |
|
440 TInt SrcSegIdx = -1; |
|
441 |
|
442 TInt cidx = 0; |
|
443 TInt didx = 0; |
|
444 |
|
445 for (TInt idx = 0; idx < nrelocs; idx++) |
|
446 { |
|
447 Elf32_Rel * rel = &iRel[idx]; |
|
448 |
|
449 if (ELF32_R_TYPE(rel->r_info) == R_ARM_RABS32) |
|
450 { |
|
451 if (iElfFile->CodeSegmentP(SrcSegIdx)) |
|
452 aCodeRelocs[cidx++]=rel; |
|
453 else if (iElfFile->DataSegmentP(SrcSegIdx)) |
|
454 aDataRelocs[didx++]=rel; |
|
455 } |
|
456 else if (ELF32_R_TYPE(rel->r_info) == R_ARM_RBASE) |
|
457 { |
|
458 SrcSegIdx = ELF32_R_SYM(rel->r_info); |
|
459 if (!(iElfFile->CodeSegmentP(SrcSegIdx-1) || iElfFile->DataSegmentP(SrcSegIdx-1))) |
|
460 { |
|
461 Print(EPeError, "Source segment for relocations is neither Code or Data.\n"); |
|
462 return EFalse; |
|
463 } |
|
464 SrcSegIdx--; |
|
465 } |
|
466 } |
|
467 |
|
468 if(!iNamedLookupEnabled) |
|
469 return ETrue; |
|
470 |
|
471 // Add the 0th ordinal of this binary - The relocation info is already setup. |
|
472 aCodeRelocs[cidx++] = &iOrdZeroRec->iReloc; |
|
473 |
|
474 // add relocation entries for each of the symbols |
|
475 NamedExportSymbol *aSym = iNamedExportSymbolHead; |
|
476 while(aSym) |
|
477 { |
|
478 // The symbol name info is part of the code section hence all relocations |
|
479 // are collected as part of Code relocations. |
|
480 aCodeRelocs[cidx++] = &aSym->iReloc; |
|
481 aSym = aSym->Next(); |
|
482 } |
|
483 |
|
484 // Since we have added a few relocations, lets make sure |
|
485 // they are still sorted on addresses they refer to. |
|
486 |
|
487 //Sorting the code relocs |
|
488 TInt aIdx1, aIdx2; |
|
489 Elf32_Rel *aTmp; |
|
490 for (aIdx1 = 0; aIdx1 < cidx; aIdx1++) { |
|
491 for (aIdx2 = aIdx1; aIdx2 < cidx; aIdx2++) { |
|
492 if(aCodeRelocs[aIdx1]->r_offset > aCodeRelocs[aIdx2]->r_offset) { |
|
493 aTmp = aCodeRelocs[aIdx2]; |
|
494 aCodeRelocs[aIdx2] = aCodeRelocs[aIdx1]; |
|
495 aCodeRelocs[aIdx1] = aTmp; |
|
496 } |
|
497 } |
|
498 } |
|
499 |
|
500 //Sorting the data relocs |
|
501 for (aIdx1 = 0; aIdx1 < didx; aIdx1++) { |
|
502 for (aIdx2 = aIdx1; aIdx2 < didx; aIdx2++) { |
|
503 if(aDataRelocs[aIdx1]->r_offset > aDataRelocs[aIdx2]->r_offset) { |
|
504 aTmp = aDataRelocs[aIdx2]; |
|
505 aDataRelocs[aIdx2] = aDataRelocs[aIdx1]; |
|
506 aDataRelocs[aIdx1] = aTmp; |
|
507 } |
|
508 } |
|
509 } |
|
510 |
|
511 return ETrue; |
|
512 } |
|
513 |
|
514 NamedExportSymbol::NamedExportSymbol(char* aName, Elf32_Addr aValue) : \ |
|
515 iSymbolName(aName), iValue(aValue), iNext(NULL) |
|
516 { |
|
517 } |
|
518 |
|
519 TBool ELFFile::ELFDllData::CreateSymLookupTable() |
|
520 { |
|
521 if( !SetupSymbolValues() ) |
|
522 return FALSE; |
|
523 |
|
524 if( !SetupSymbolNames() ) |
|
525 return FALSE; |
|
526 |
|
527 return TRUE; |
|
528 } |
|
529 |
|
530 TBool ELFFile::ELFDllData::SetupSymbolValues() |
|
531 { |
|
532 NamedExportSymbol *aSym, *aPrevSym; |
|
533 |
|
534 if( int(iExportTableSymIdx) == -1 || int(iExportTableSizeSymIdx) == -1) |
|
535 return FALSE; |
|
536 |
|
537 // Fetch the 'export table' symbol from the dynamic symbol table. |
|
538 Elf32_Sym *aElfExpTbl = &iDynSymTab[iExportTableSymIdx]; |
|
539 |
|
540 // Fetch the 'export table size' symbol from the dynamic symbol table. |
|
541 Elf32_Sym *aElfExpTblSz = &iDynSymTab[iExportTableSizeSymIdx]; |
|
542 |
|
543 if((aElfExpTbl->st_value - aElfExpTblSz->st_value) != 4) |
|
544 { |
|
545 // Check that the word prior to the export table is not the export table size |
|
546 // This is to make sure that there is space for the 0th ordinal and |
|
547 // we dont overwrite the 'export table size' entry. |
|
548 iNamedLookupEnabled = 1; |
|
549 } |
|
550 else |
|
551 return FALSE; |
|
552 |
|
553 // Fetch the export table contents |
|
554 Elf32_Word * aExpEntries = iElfFile->CodePtrFromAddr(aElfExpTbl->st_value); |
|
555 |
|
556 if(!aExpEntries) |
|
557 return FALSE; |
|
558 |
|
559 aSym = aPrevSym = NULL; |
|
560 TInt idx; |
|
561 // Create symbols corresponding to export table entries. |
|
562 for(idx = 0; idx < iNumberOfExports; idx++) |
|
563 { |
|
564 //Symbols marked Absent are ignored. |
|
565 if( aExpEntries[idx] == iElfFile->iEntryPoint) |
|
566 continue; |
|
567 |
|
568 aSym = new NamedExportSymbol(0, aExpEntries[idx]); |
|
569 iNamedExportCount++; |
|
570 if(aPrevSym) |
|
571 { |
|
572 aPrevSym->Next(aSym); |
|
573 } |
|
574 else |
|
575 { |
|
576 iNamedExportSymbolHead = aSym; |
|
577 } |
|
578 |
|
579 aPrevSym = aSym; |
|
580 } |
|
581 |
|
582 return TRUE; |
|
583 } |
|
584 |
|
585 TBool ELFFile::ELFDllData::SetupSymbolNames() |
|
586 { |
|
587 char *aSymName = NULL; |
|
588 NamedExportSymbol *aSym; |
|
589 TUint aDynSymbolTblCount = iHashTable->nChains; |
|
590 TInt aCount = 0; |
|
591 TInt aCodeSegIdx = iElfFile->CodeSegmentIndex() + 1; |
|
592 TInt aDataSegIdx = iElfFile->DataSegmentIndex() + 1; |
|
593 |
|
594 // Traverse the dynamic symbol table |
|
595 for(TUint idx = 0; idx < aDynSymbolTblCount; idx++) |
|
596 { |
|
597 //Consider only the the defined symbols |
|
598 if( ELF32_ST_TYPE(iDynSymTab[idx].st_info) == STT_OBJECT || |
|
599 ELF32_ST_TYPE(iDynSymTab[idx].st_info) == STT_FUNC ) |
|
600 { |
|
601 aSym = iNamedExportSymbolHead; |
|
602 while(aSym) |
|
603 { |
|
604 // Name already set |
|
605 if(aSym->Name()) |
|
606 { |
|
607 aSym = aSym->Next(); |
|
608 continue; |
|
609 } |
|
610 Elf32_Addr aAddr = aSym->Value(); |
|
611 |
|
612 // If the exported symbol and the dynamic symbol table entry have the |
|
613 // same values, setup the name |
|
614 if(iDynSymTab[idx].st_value == aAddr) |
|
615 { |
|
616 aSymName = ELFADDR(char, iDynStrTab, iDynSymTab[idx].st_name); |
|
617 aSym->Name(aSymName); |
|
618 |
|
619 if(iElfFile->CodeSegmentP (iElfFile->GetSegmentFromAddr(aAddr)) ) { |
|
620 aSym->iReloc.r_info = aCodeSegIdx << 8 | R_ARM_RABS32; |
|
621 aSym->iSymRelocType = KTextRelocType; |
|
622 } |
|
623 else { |
|
624 aSym->iReloc.r_info = aDataSegIdx << 8 | R_ARM_RABS32; |
|
625 aSym->iSymRelocType = KDataRelocType; |
|
626 } |
|
627 |
|
628 iNumberOfCodeRelocs++; |
|
629 iNumberOfRelocs++; |
|
630 |
|
631 // The offset to the name is always 4 byte aligned. |
|
632 iStringNameOffset = iSymStringTableSize >> 2; |
|
633 aSym->NameOffset( iSymStringTableSize ); |
|
634 // These are NULL-terminated strings |
|
635 iSymStringTableSize += (strlen(aSymName) + 1); |
|
636 iSymStringTableSize = ALIGN4(iSymStringTableSize); |
|
637 |
|
638 aCount++; |
|
639 break; |
|
640 } |
|
641 aSym = aSym->Next(); |
|
642 } |
|
643 } |
|
644 } |
|
645 |
|
646 if(aCount != iNamedExportCount) |
|
647 return FALSE; |
|
648 |
|
649 // Sort symbols on their names... |
|
650 if(iNamedExportCount > 1) |
|
651 { |
|
652 NamedExportSymbol **aTmpStart = &iNamedExportSymbolHead; |
|
653 Sort(aTmpStart, iNamedExportSymbolHead); |
|
654 } |
|
655 |
|
656 return TRUE; |
|
657 } |
|
658 |
|
659 void ELFFile::ELFDllData::SetLookupTblBase(TInt aBaseOffset) |
|
660 { |
|
661 Elf32_Addr aBaseAddr = iElfFile->iLinkedBase + iElfFile->GetCodeSize(); |
|
662 |
|
663 Elf32_Addr aAddr; |
|
664 |
|
665 // setup relocations of each of the exported symbols. |
|
666 aAddr = aBaseAddr + iSymInfoHdr.iSymbolTblOffset; |
|
667 NamedExportSymbol *aSym = iNamedExportSymbolHead; |
|
668 while(aSym) |
|
669 { |
|
670 aSym->iReloc.r_offset = aAddr; |
|
671 aAddr += sizeof(Elf32_Addr); |
|
672 aSym = aSym->Next(); |
|
673 } |
|
674 |
|
675 // setup relocations for the 0th ordinal of this binary. |
|
676 |
|
677 iOrdZeroRec = new OrdZeroRecord(0); |
|
678 Elf32_Sym * et = &iDynSymTab[iExportTableSymIdx]; |
|
679 iOrdZeroRec->iReloc.r_offset = et->st_value - 4; // The word prior ro the first entry |
|
680 // of the export table is the 0th ordinal entry. |
|
681 |
|
682 //At the 0th ordinal, write the address of the start of symbol info |
|
683 TUint32 aZeroOrdOff = et->st_value - 4 - iElfFile->iLinkedBase; |
|
684 aZeroOrdOff += (iElfFile->GetSegment(et->st_shndx - 1))->p_offset; |
|
685 TUint32 *aZeroOrdLocation = ELFADDR(TUint32, iElfFile->ELFFileBase(), aZeroOrdOff); |
|
686 *aZeroOrdLocation = aBaseAddr; |
|
687 |
|
688 iOrdZeroRec->iReloc.r_info = ELF32_R_INFO(et->st_shndx, R_ARM_RABS32); |
|
689 iNumberOfCodeRelocs++; |
|
690 iNumberOfRelocs++; |
|
691 |
|
692 TInt aOffset = aBaseOffset + iSymInfoHdr.iDepDllZeroOrdTableOffset; |
|
693 |
|
694 OrdZeroRecord *aDepRecord = iDepRecords; |
|
695 |
|
696 while( aDepRecord ) |
|
697 { |
|
698 // Setup the offset - This offset (relative code segment) is filled in the |
|
699 // import table to point to this dependency record. |
|
700 aDepRecord->iOffset = aOffset; |
|
701 |
|
702 aOffset += 4; |
|
703 aDepRecord = aDepRecord->iNext; |
|
704 } |
|
705 } |
|
706 |
|
707 TBool ELFFile::ELFDllData::AddToDependency(TUint aOff) |
|
708 { |
|
709 // Add the name found in DT_NEEDED into a list. |
|
710 // The dynamic string table might not have been found in dynamic table yet. |
|
711 // So store the offset (wrt base of dynamic string table) for now. |
|
712 NeededDLLsList *aNeeded = new NeededDLLsList(aOff); |
|
713 if(!aNeeded) |
|
714 return FALSE; |
|
715 |
|
716 if ( iNeededDllNames ) { |
|
717 iNeededDllNamesTail->iNext= aNeeded; |
|
718 iNeededDllNamesTail = aNeeded; |
|
719 } |
|
720 else { |
|
721 iNeededDllNames = iNeededDllNamesTail = aNeeded; |
|
722 } |
|
723 |
|
724 return TRUE; |
|
725 } |
|
726 |
|
727 TBool ELFFile::ELFDllData::CreateDependency() |
|
728 { |
|
729 OrdZeroRecord *aDep; |
|
730 NeededDLLsList *aNeeded = iNeededDllNames; |
|
731 char *aDllName = NULL; |
|
732 DllRec *aRec; |
|
733 TInt aNeededFound; |
|
734 |
|
735 for(aNeededFound = 0; (aNeededFound < iNumberOfImportDlls) && aNeeded;) |
|
736 { |
|
737 aRec = 0; |
|
738 while(aNeeded) { |
|
739 aDllName = iDynStrTab + aNeeded->iOffset; |
|
740 // aNeeded is just a guess that this binary might be dependent on aDllName |
|
741 // Search through the import table to find if the guess was correct. |
|
742 aRec = SearchImports(aDllName); |
|
743 if(aRec && FindDependency(aRec->iName, aRec->iLen) == NULL) { |
|
744 // Check if aDllName is listed in import table and it |
|
745 // not added already in the depedency records. |
|
746 aNeededFound++; |
|
747 break; |
|
748 } |
|
749 // Bad guess...go to the next aNeeded |
|
750 aNeeded = aNeeded->iNext; |
|
751 } |
|
752 |
|
753 if( !aRec ) |
|
754 return FALSE; |
|
755 |
|
756 aDep = new OrdZeroRecord(aDllName); |
|
757 if(!iDepRecords) |
|
758 { |
|
759 iDepRecords = iDepRecordsTail = aDep; |
|
760 } |
|
761 else |
|
762 { |
|
763 iDepRecordsTail->iNext = aDep; |
|
764 iDepRecordsTail = aDep; |
|
765 } |
|
766 aNeeded = aNeeded->iNext; |
|
767 } |
|
768 |
|
769 return (aNeededFound == iNumberOfImportDlls); |
|
770 } |
|
771 |
|
772 ELFFile::ELFDllData::DllRec* ELFFile::ELFDllData::SearchImports(char *aName) |
|
773 { |
|
774 DllRec *aRec = iDllHead; |
|
775 while (aRec) |
|
776 { |
|
777 if(strncmp(aRec->iName, aName, aRec->iLen) == 0) |
|
778 return aRec; |
|
779 aRec = aRec->iNext; |
|
780 } |
|
781 return NULL; |
|
782 } |
|
783 |
|
784 OrdZeroRecord* ELFFile::ELFDllData::FindDependency(char* aName, TUint aLen) |
|
785 { |
|
786 OrdZeroRecord* aDep = iDepRecords; |
|
787 while(aDep) |
|
788 { |
|
789 if(strncmp(aName, aDep->iName, aLen) == 0) |
|
790 return aDep; |
|
791 aDep = aDep->iNext; |
|
792 } |
|
793 return NULL; |
|
794 } |
|
795 |
|
796 void ELFFile::ELFDllData::GetExportSymInfoHeader(E32EpocExpSymInfoHdr& aSymInfoHdr) |
|
797 { |
|
798 memcpy(&aSymInfoHdr, &iSymInfoHdr, sizeof(E32EpocExpSymInfoHdr)); |
|
799 } |
|
800 |
|
801 void ELFFile::ELFDllData::SetExportSymInfo() |
|
802 { |
|
803 iSymInfoHdr.iSymCount = (TUint16)iNamedExportCount; |
|
804 iSymInfoHdr.iSymbolTblOffset = sizeof(E32EpocExpSymInfoHdr); |
|
805 iSymInfoHdr.iStringTableSz = iSymStringTableSize; |
|
806 TInt aSymTabSz; |
|
807 if( iStringNameOffset > 0xffff){ |
|
808 iSymInfoHdr.iFlags = KNameLookupOffsetFlag32; // Flag indicating 32 bit offsets |
|
809 // for symbol names |
|
810 aSymTabSz = iNamedExportCount* sizeof(TUint32);// symbol addresses |
|
811 aSymTabSz += iNamedExportCount* sizeof(TUint32);// symbol name 32-bit offsets |
|
812 } |
|
813 else |
|
814 { |
|
815 iSymInfoHdr.iFlags &= ~KNameLookupOffsetFlag32;// Flag indicating 16-bit offsets |
|
816 // for symbol names |
|
817 aSymTabSz = iNamedExportCount* sizeof(TUint32); // symbol addresses |
|
818 aSymTabSz += iNamedExportCount* sizeof(TUint16);// symbol name 16-bit offsets |
|
819 aSymTabSz = ALIGN4(aSymTabSz); |
|
820 } |
|
821 iSymInfoHdr.iStringTableOffset = iSymInfoHdr.iSymbolTblOffset + aSymTabSz; |
|
822 iSymInfoHdr.iDllCount = iNumberOfImportDlls; |
|
823 iSymInfoHdr.iDepDllZeroOrdTableOffset = iSymInfoHdr.iStringTableOffset + \ |
|
824 iSymInfoHdr.iStringTableSz; |
|
825 |
|
826 iSymInfoHdr.iSize = iSymInfoHdr.iDepDllZeroOrdTableOffset + \ |
|
827 iSymInfoHdr.iDllCount * sizeof(Elf32_Addr); |
|
828 } |
|
829 |
|
830 TUint ELFFile::ELFDllData::GetSymLookupSection(char* aBuff) |
|
831 { |
|
832 if( !iNamedLookupEnabled) |
|
833 return 0; |
|
834 |
|
835 memcpy(aBuff, &iSymInfoHdr, sizeof(iSymInfoHdr)); |
|
836 |
|
837 // Name offsets start after the end of symbol addresses. |
|
838 TUint32 aNameOffsetStart = iSymInfoHdr.iSymbolTblOffset + \ |
|
839 iNamedExportCount* sizeof(TUint32); |
|
840 |
|
841 TUint32 *aAddrPtr = (TUint32*)(aBuff + iSymInfoHdr.iSymbolTblOffset); |
|
842 TUint32 aStringTabOff = 0; |
|
843 char *aStringTab = aBuff + iSymInfoHdr.iStringTableOffset;//Start of the string table. |
|
844 NamedExportSymbol *aSym = iNamedExportSymbolHead; |
|
845 while(aSym) |
|
846 { |
|
847 *aAddrPtr = aSym->Value(); |
|
848 aStringTabOff = aSym->NameOffset(); // Get the offset of symbol name (which is wrt |
|
849 // string table base). |
|
850 if( iSymInfoHdr.iFlags & KNameLookupOffsetFlag32 ) |
|
851 { |
|
852 TUint32 *aNameOffPtr = (TUint32*)(aBuff + aNameOffsetStart); |
|
853 *aNameOffPtr = (aStringTabOff >> 2);//write the offset of the name |
|
854 strcpy(aStringTab + aStringTabOff, aSym->Name());//write the symbol name |
|
855 aNameOffsetStart +=4; |
|
856 } |
|
857 else |
|
858 { |
|
859 TUint16 *aNameOffPtr = (TUint16*)(aBuff + aNameOffsetStart); |
|
860 *aNameOffPtr = (TUint16)(aStringTabOff >> 2);//write the offset of the name |
|
861 strcpy(aStringTab + aStringTabOff, aSym->Name());//write the symbol name |
|
862 aNameOffsetStart +=2; |
|
863 } |
|
864 aAddrPtr++; |
|
865 aSym = aSym->Next(); |
|
866 } |
|
867 |
|
868 OrdZeroRecord *aRec = iDepRecords; |
|
869 TUint32* aDepsTable = (TUint32*)(aBuff + iSymInfoHdr.iDepDllZeroOrdTableOffset); |
|
870 while(aRec) |
|
871 { |
|
872 *aDepsTable++ = 0; |
|
873 aRec = aRec->iNext; |
|
874 } |
|
875 return iSymInfoHdr.iSize; |
|
876 } |
|
877 |
|
878 void ELFFile::ELFDllData::Sort(NamedExportSymbol** aDstList, NamedExportSymbol* aSrcList) |
|
879 { |
|
880 NamedExportSymbol *aSym = aSrcList; |
|
881 NamedExportSymbol **aSymbols = new NamedExportSymbol*[iNamedExportCount]; |
|
882 |
|
883 TInt pos; |
|
884 for (pos = 0; pos < iNamedExportCount; pos++) { |
|
885 aSymbols[pos] = aSym; |
|
886 aSym = aSym->Next(); |
|
887 } |
|
888 |
|
889 NamedExportSymbol **aResult = new NamedExportSymbol*[iNamedExportCount]; |
|
890 MergeSort(aResult, aSymbols); |
|
891 iNamedExportSymbolHead = aResult[0]; |
|
892 for (pos = 0; pos < iNamedExportCount; pos++) { |
|
893 aSym = aResult[pos]; |
|
894 if( pos == iNamedExportCount-1) |
|
895 aSym->Next(NULL); |
|
896 else |
|
897 aSym->Next(aResult[pos+1]); |
|
898 } |
|
899 *aDstList = aResult[0]; |
|
900 delete [] aResult; |
|
901 delete [] aSymbols; |
|
902 } |
|
903 |
|
904 void ELFFile::ELFDllData::MergeSort(NamedExportSymbol** aDstList, NamedExportSymbol** aSrcList) |
|
905 { |
|
906 MergeSort(aDstList, aSrcList, 0, iNamedExportCount); |
|
907 } |
|
908 |
|
909 void ELFFile::ELFDllData::MergeSort(NamedExportSymbol** aDstList, NamedExportSymbol** aSrcList, \ |
|
910 TUint aLeft, TUint aRight) |
|
911 { |
|
912 if( (aRight - aLeft) <= 1) |
|
913 return; |
|
914 |
|
915 TUint aSize = aRight - aLeft; |
|
916 TUint aCenter = aLeft + aSize/2; |
|
917 |
|
918 MergeSort(aDstList, aSrcList, aLeft, aCenter); |
|
919 MergeSort(aDstList, aSrcList, aCenter, aRight); |
|
920 |
|
921 TUint aLPos, aRPos, aCnt; |
|
922 aLPos = aLeft; |
|
923 aRPos = aCenter; |
|
924 for(aCnt = 0; aCnt < aSize; aCnt++) |
|
925 { |
|
926 if( (aLPos < aCenter) && |
|
927 (aRPos == aRight || (strcmp(aSrcList[aLPos]->Name(), aSrcList[aRPos]->Name()) < 0) ) |
|
928 ) |
|
929 { |
|
930 // Compare the left half with the right and add the lesser one. |
|
931 // The comparision is done on the topmost element on each half. |
|
932 // if aRPos is past the last element of the right half, the left element has |
|
933 // nothing to compare with. Just add it to the result list. |
|
934 aDstList[aCnt] = aSrcList[aLPos]; |
|
935 aLPos++; |
|
936 } |
|
937 else |
|
938 { |
|
939 // Add the greater one into the list. |
|
940 // if aLPos is past the element at the center, it anyway belongs to the |
|
941 // right half. Add it to the result list. |
|
942 aDstList[aCnt] = aSrcList[aRPos]; |
|
943 aRPos++; |
|
944 } |
|
945 } |
|
946 |
|
947 // Once the sublist is sorted, put it back to the source list |
|
948 // so that the parent has its left and right sublists are sorted. |
|
949 for(aCnt = 0; aCnt < aSize; aCnt++) |
|
950 { |
|
951 aSrcList[aLeft+aCnt] = aDstList[aCnt]; |
|
952 } |
|
953 } |
|
954 |