Debugging a segfault in ELF loader (when loading CLIShell)
[tpg/acess2.git] / AcessNative / ld-acess_src / elf.c
1 /*\r
2  * Acess v0.1\r
3  * ELF Executable Loader Code\r
4  */\r
5 #define DEBUG   1\r
6 #include <stdlib.h>\r
7 #include <stdio.h>\r
8 #include <string.h>\r
9 #include <unistd.h>\r
10 #include "common.h"\r
11 #include "elf.h"\r
12 \r
13 #define DEBUG_WARN      1\r
14 \r
15 #define MKPTR(_type,_val)       ((_type*)(uintptr_t)(_val))\r
16 #define PTRMK(_type,_val)       MKPTR(_type,_val)\r
17 #define PTR(_val)       ((void*)(uintptr_t)(_val))\r
18 \r
19 #if DEBUG\r
20 # define ENTER(...)\r
21 # define LOG(s, ...)    printf("%s: " s, __func__, __VA_ARGS__)\r
22 # define LOGS(s)        printf("%s: " s, __func__)\r
23 # define LEAVE(...)\r
24 #else\r
25 # define ENTER(...)\r
26 # define LOG(...)\r
27 # define LOGS(...)\r
28 # define LEAVE(...)\r
29 #endif\r
30 \r
31 // === PROTOTYPES ===\r
32 void    *Elf_Load(int FD);\r
33 uintptr_t       Elf_Relocate(void *Base);\r
34  int    Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret);\r
35  int    Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *Base);\r
36 uint32_t        Elf_Int_HashString(char *str);\r
37 \r
38 // === CODE ===\r
39 void *Elf_Load(int FD)\r
40 {\r
41         Elf32_Ehdr      hdr;\r
42         Elf32_Phdr      *phtab;\r
43          int    i, j;\r
44          int    iPageCount;\r
45         uint32_t        max, base;\r
46         uint32_t        addr;\r
47         uint32_t        baseDiff = 0;\r
48         \r
49         ENTER("iFD", FD);\r
50         \r
51         // Read ELF Header\r
52         acess_read(FD, sizeof(hdr), &hdr);\r
53         \r
54         // Check the file type\r
55         if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {\r
56                 Warning("Non-ELF File was passed to the ELF loader\n");\r
57                 LEAVE('n');\r
58                 return NULL;\r
59         }\r
60         \r
61         // Check for a program header\r
62         if(hdr.phoff == 0) {\r
63                 #if DEBUG_WARN\r
64                 Warning("ELF File does not contain a program header\n");\r
65                 #endif\r
66                 LEAVE('n');\r
67                 return NULL;\r
68         }\r
69         \r
70         // Read Program Header Table\r
71         phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount );\r
72         if( !phtab ) {\r
73                 LEAVE('n');\r
74                 return NULL;\r
75         }\r
76         LOG("hdr.phoff = 0x%08x\n", hdr.phoff);\r
77         acess_seek(FD, hdr.phoff, ACESS_SEEK_SET);\r
78         acess_read(FD, sizeof(Elf32_Phdr) * hdr.phentcount, phtab);\r
79         \r
80         // Count Pages\r
81         iPageCount = 0;\r
82         LOG("hdr.phentcount = %i\n", hdr.phentcount);\r
83         for( i = 0; i < hdr.phentcount; i++ )\r
84         {\r
85                 // Ignore Non-LOAD types\r
86                 if(phtab[i].Type != PT_LOAD)\r
87                         continue;\r
88                 iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;\r
89                 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}\n", i, phtab[i].VAddr, phtab[i].MemSize);\r
90         }\r
91         \r
92         LOG("iPageCount = %i\n", iPageCount);\r
93         \r
94         // Allocate Information Structure\r
95         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
96         // Fill Info Struct\r
97         //ret->Entry = hdr.entrypoint;\r
98         //ret->Base = -1;               // Set Base to maximum value\r
99         //ret->NumPages = iPageCount;\r
100         //ret->Interpreter = NULL;\r
101 \r
102         // Prescan for base and size\r
103         max = 0;\r
104         base = 0xFFFFFFFF;\r
105         for( i = 0; i < hdr.phentcount; i ++)\r
106         {\r
107                 if( phtab[i].Type != PT_LOAD )\r
108                         continue;\r
109                 if( phtab[i].VAddr < base )\r
110                         base = phtab[i].VAddr;\r
111                 if( phtab[i].VAddr > max )\r
112                         max = phtab[i].VAddr;\r
113         }\r
114 \r
115         LOG("base = %08x, max = %08x\n", base, max);\r
116 \r
117         if( base == 0 ) {\r
118                 // Find a nice space (31 address bits allowed)\r
119                 base = FindFreeRange( max, 31 );\r
120                 LOG("new base = %08x\n", base);\r
121                 if( base == 0 ) return NULL;\r
122                 baseDiff = base;\r
123         }\r
124         \r
125         // Load Pages\r
126         j = 0;\r
127         for( i = 0; i < hdr.phentcount; i++ )\r
128         {\r
129                 //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
130                 LOG("phtab[%i] = {\n", i);\r
131                 LOG(" .Type = 0x%08x\n", phtab[i].Type);\r
132                 LOG(" .Offset = 0x%08x\n", phtab[i].Offset);\r
133                 LOG(" .VAddr = 0x%08x\n", phtab[i].VAddr);\r
134                 LOG(" .PAddr = 0x%08x\n", phtab[i].PAddr);\r
135                 LOG(" .FileSize = 0x%08x\n", phtab[i].FileSize);\r
136                 LOG(" .MemSize = 0x%08x\n", phtab[i].MemSize);\r
137                 LOG(" .Flags = 0x%08x\n", phtab[i].Flags);\r
138                 LOG(" .Align = 0x%08x\n", phtab[i].Align);\r
139                 LOGS(" }\n");\r
140                 // Get Interpreter Name\r
141                 if( phtab[i].Type == PT_INTERP )\r
142                 {\r
143                         char *tmp;\r
144                         //if(ret->Interpreter)  continue;\r
145                         tmp = malloc(phtab[i].FileSize);\r
146                         acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
147                         acess_read(FD, phtab[i].FileSize, tmp);\r
148                         //ret->Interpreter = Binary_RegInterp(tmp);\r
149                         LOG("Interpreter '%s'\n", tmp);\r
150                         free(tmp);\r
151                         continue;\r
152                 }\r
153                 // Ignore non-LOAD types\r
154                 if(phtab[i].Type != PT_LOAD)    continue;\r
155                 \r
156                 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}\n",\r
157                         i, phtab[i].VAddr+baseDiff, phtab[i].Offset, phtab[i].FileSize);\r
158                 \r
159                 addr = phtab[i].VAddr + baseDiff;\r
160 \r
161                 if( AllocateMemory( addr, phtab[i].MemSize ) ) {\r
162                         fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",\r
163                                 addr, phtab[i].MemSize);\r
164                         free( phtab );\r
165                         return NULL;\r
166                 }\r
167                 \r
168                 acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
169                 acess_read(FD, phtab[i].FileSize, PTRMK(void, addr) );\r
170                 memset( PTRMK(char, addr) + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize );\r
171         }\r
172         \r
173         // Clean Up\r
174         free(phtab);\r
175         // Return\r
176         LEAVE('p', base);\r
177         return PTRMK(void, base);\r
178 }\r
179 \r
180 // --- ELF RELOCATION ---\r
181 /**\r
182  * \brief Relocates a loaded ELF Executable\r
183  */\r
184 uintptr_t Elf_Relocate(void *Base)\r
185 {\r
186         Elf32_Ehdr      *hdr = Base;\r
187         Elf32_Phdr      *phtab;\r
188          int    i, j;   // Counters\r
189         char    *libPath;\r
190         uint32_t        iRealBase = -1;\r
191         uintptr_t       iBaseDiff;\r
192          int    iSegmentCount;\r
193          int    iSymCount = 0;\r
194         Elf32_Rel       *rel = NULL;\r
195         Elf32_Rela      *rela = NULL;\r
196         uint32_t        *pltgot = NULL;\r
197         void    *plt = NULL;\r
198         uint32_t        *ptr;\r
199          int    relSz=0, relEntSz=8;\r
200          int    relaSz=0, relaEntSz=8;\r
201          int    pltSz=0, pltType=0;\r
202         Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer\r
203         char    *dynstrtab = NULL;      // .dynamic String Table\r
204         Elf32_Sym       *dynsymtab = NULL;\r
205          int    bFailed = 0;\r
206         \r
207         ENTER("pBase", Base);\r
208         LOG("Base = %p\n", Base);\r
209         \r
210         // Parse Program Header to get Dynamic Table\r
211         phtab = Base + hdr->phoff;\r
212         iSegmentCount = hdr->phentcount;\r
213         for(i = 0; i < iSegmentCount; i ++ )\r
214         {\r
215                 // Determine linked base address\r
216                 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
217                         iRealBase = phtab[i].VAddr;\r
218                 \r
219                 // Find Dynamic Section\r
220                 if(phtab[i].Type == PT_DYNAMIC) {\r
221                         if(dynamicTab) {\r
222                                 Warning("Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
223                                 continue;\r
224                         }\r
225                         dynamicTab = MKPTR(void, phtab[i].VAddr);\r
226                         j = i;  // Save Dynamic Table ID\r
227                         break;\r
228                 }\r
229         }\r
230         \r
231         // Check if a PT_DYNAMIC segement was found\r
232         if(!dynamicTab) {\r
233                 Warning("Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
234                 LEAVE('x', hdr->entrypoint);\r
235                 return hdr->entrypoint;\r
236         }\r
237         \r
238         // Page Align real base\r
239         iRealBase &= ~0xFFF;\r
240         \r
241         LOG("dynamicTab = %p\n", dynamicTab);\r
242         // Adjust "Real" Base\r
243         iBaseDiff = (uintptr_t)Base - iRealBase;\r
244         LOG("iBaseDiff = %p\n", (void*)iBaseDiff);\r
245         // Adjust Dynamic Table\r
246         dynamicTab = PTR( (uintptr_t)dynamicTab + iBaseDiff);\r
247         LOG("dynamicTab = %p\n", dynamicTab);\r
248 \r
249         hdr->entrypoint += iBaseDiff;\r
250         \r
251         hdr->misc.SymTable = 0;\r
252         hdr->misc.HashTable = 0;\r
253         \r
254         // === Get Symbol table and String Table ===\r
255         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
256         {\r
257                 switch(dynamicTab[j].d_tag)\r
258                 {\r
259                 // --- Symbol Table ---\r
260                 case DT_SYMTAB:\r
261                         dynamicTab[j].d_val += iBaseDiff;\r
262                         dynsymtab = PTRMK(void, dynamicTab[j].d_val);\r
263                         hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
264                         break;\r
265                 \r
266                 // --- String Table ---\r
267                 case DT_STRTAB:\r
268                         dynamicTab[j].d_val += iBaseDiff;\r
269                         dynstrtab = PTRMK(void, dynamicTab[j].d_val);\r
270                         break;\r
271                 \r
272                 // --- Hash Table --\r
273                 case DT_HASH:\r
274                         dynamicTab[j].d_val += iBaseDiff;\r
275                         iSymCount = (PTRMK(uint32_t, dynamicTab[j].d_val))[1];\r
276                         hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
277                         break;\r
278                 }\r
279         }\r
280         \r
281         LOG("hdr->misc.SymTable = %x, hdr->misc.HashTable = %x",\r
282                 hdr->misc.SymTable, hdr->misc.HashTable);\r
283 \r
284 \r
285         // Alter Symbols to true base\r
286         for(i = 0; i < iSymCount; i ++)\r
287         {\r
288                 dynsymtab[i].nameOfs += (uintptr_t)dynstrtab;\r
289                 if( dynsymtab[i].shndx == SHN_UNDEF )\r
290                 {\r
291                         LOG("Sym '%s' = UNDEF\n", MKPTR(char,dynsymtab[i].name));\r
292                 }\r
293                 else\r
294                 {\r
295                         dynsymtab[i].value += iBaseDiff;\r
296                         LOG("Sym '%s' = 0x%x (relocated)\n", MKPTR(char,dynsymtab[i].name), dynsymtab[i].value);\r
297                 }\r
298         }\r
299         \r
300         // === Add to loaded list (can be imported now) ===\r
301         Binary_SetReadyToUse( Base );\r
302 \r
303         // === Parse Relocation Data ===\r
304         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
305         {\r
306                 switch(dynamicTab[j].d_tag)\r
307                 {\r
308                 // --- Shared Library Name ---\r
309                 case DT_SONAME:\r
310                         LOG(".so Name '%s'\n", dynstrtab + dynamicTab[j].d_val);\r
311                         break;\r
312                 // --- Needed Library ---\r
313                 case DT_NEEDED:\r
314                         libPath = dynstrtab + dynamicTab[j].d_val;\r
315                         Binary_LoadLibrary(libPath);\r
316                         break;\r
317                 // --- PLT/GOT ---\r
318                 case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val);        break;\r
319                 case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val);   break;\r
320                 case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;\r
321                 case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;\r
322                 \r
323                 // --- Relocation ---\r
324                 case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
325                 case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;\r
326                 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
327                 \r
328                 case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;\r
329                 case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;\r
330                 case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;\r
331                 }\r
332         }\r
333         \r
334         // Parse Relocation Entries\r
335         if(rel && relSz)\r
336         {\r
337                 j = relSz / relEntSz;\r
338                 for( i = 0; i < j; i++ )\r
339                 {\r
340                         ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
341                         if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {\r
342                                 bFailed = 1;\r
343                         }\r
344                 }\r
345         }\r
346         // Parse Relocation Entries\r
347         if(rela && relaSz)\r
348         {\r
349                 j = relaSz / relaEntSz;\r
350                 for( i = 0; i < j; i++ )\r
351                 {\r
352                         ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
353                         if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, Base) ) {\r
354                                 bFailed = 1;\r
355                         }\r
356                 }\r
357         }\r
358         \r
359         // === Process PLT (Procedure Linkage Table) ===\r
360         if(plt && pltSz)\r
361         {\r
362                 if(pltType == DT_REL)\r
363                 {\r
364                         Elf32_Rel       *pltRel = plt;\r
365                         j = pltSz / sizeof(Elf32_Rel);\r
366                         LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);\r
367                         for(i = 0; i < j; i++)\r
368                         {\r
369                                 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
370                                 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {\r
371                                         bFailed = 1;\r
372                                 }\r
373                         }\r
374                 }\r
375                 else\r
376                 {\r
377                         Elf32_Rela      *pltRela = plt;\r
378                         j = pltSz / sizeof(Elf32_Rela);\r
379                         LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);\r
380                         for(i=0;i<j;i++)\r
381                         {\r
382                                 ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
383                                 if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, Base) ) {\r
384                                         bFailed = 1;\r
385                                 }\r
386                         }\r
387                 }\r
388         }\r
389         \r
390         if(bFailed) {\r
391                 LEAVE('i', 0);\r
392                 return 0;\r
393         }\r
394         \r
395         LEAVE('x', hdr->entrypoint);\r
396         return hdr->entrypoint;\r
397 }\r
398 \r
399 /**\r
400  * \fn void Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)\r
401  * \brief Performs a relocation\r
402  * \param r_info        Field from relocation entry\r
403  * \param ptr   Pointer to location of relocation\r
404  * \param addend        Value to add to symbol\r
405  * \param symtab        Symbol Table\r
406  * \param base  Base of loaded binary\r
407  */\r
408 int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)\r
409 {\r
410         uintptr_t       val;\r
411          int    type = ELF32_R_TYPE(r_info);\r
412          int    sym = ELF32_R_SYM(r_info);\r
413         char    *sSymName = PTRMK(char, symtab[sym].name);\r
414         \r
415         //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
416         //      r_info, ptr, addend, base);\r
417         \r
418         switch( type )\r
419         {\r
420         // Standard 32 Bit Relocation (S+A)\r
421         case R_386_32:\r
422                 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
423                         Warning("Unable to find symbol '%s'", sSymName);\r
424                         return 0;\r
425                 }\r
426                 LOG("%08x R_386_32 *%p += %p('%s')\n", r_info, ptr, (void*)val, sSymName);\r
427                 *ptr = val + addend;\r
428                 break;\r
429                 \r
430         // 32 Bit Relocation wrt. Offset (S+A-P)\r
431         case R_386_PC32:\r
432                 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
433                         Warning("Unable to find symbol '%s'", sSymName);\r
434                         return 0;\r
435                 }\r
436                 LOG("%08x R_386_PC32 *%p = 0x%x + %p('%s') - %p\n", r_info, ptr, *ptr, (void*)val, sSymName, ptr );\r
437                 // TODO: Check if it needs the true value of ptr or the compiled value\r
438                 // NOTE: Testing using true value\r
439                 *ptr = val + addend - (uintptr_t)ptr;\r
440                 break;\r
441 \r
442         // Absolute Value of a symbol (S)\r
443         case R_386_GLOB_DAT:\r
444                 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
445                         Warning("Unable to find symbol '%s'", sSymName);\r
446                         return 0; \r
447                 }\r
448                 LOG("%08x R_386_GLOB_DAT *%p = 0x%x(%s)\n", r_info, ptr, (unsigned int)val, sSymName);\r
449                 *ptr = val;\r
450                 break;\r
451         \r
452         // Absolute Value of a symbol (S)\r
453         case R_386_JMP_SLOT:\r
454                 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
455                         Warning("Unable to find symbol '%s'", sSymName);\r
456                         return 0;\r
457                 }\r
458                 LOG("%08x R_386_JMP_SLOT *%p = 0x%x (%s)\n", r_info, ptr, (unsigned int)val, sSymName);\r
459                 *ptr = val;\r
460                 break;\r
461 \r
462         // Base Address (B+A)\r
463         case R_386_RELATIVE:\r
464                 LOG("%08x R_386_RELATIVE *%p = %p + 0x%x\n", r_info, ptr, base, addend);\r
465                 *ptr = (uintptr_t)base + addend;\r
466                 break;\r
467                 \r
468         default:\r
469                 LOG("Rel %p: 0x%x,%i\n", ptr, sym, type);\r
470                 break;\r
471         }\r
472         return 1;\r
473 }\r
474 \r
475 /**\r
476  * \fn int Elf_GetSymbol(void *Base, char *name, uintptr_t *ret)\r
477  * \brief Get a symbol from the loaded binary\r
478  */\r
479 int Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret)\r
480 {\r
481         Elf32_Ehdr      *hdr = (void*)Base;\r
482         Elf32_Sym       *symtab;\r
483          int    nbuckets = 0;\r
484          int    iSymCount = 0;\r
485          int    i;\r
486         uint32_t        *pBuckets;\r
487         uint32_t        *pChains;\r
488         uint32_t        iNameHash;\r
489 \r
490         if(!Base)       return 0;\r
491 \r
492         pBuckets = PTR(hdr->misc.HashTable);\r
493         symtab = PTR(hdr->misc.SymTable);\r
494         \r
495         if(!pBuckets || !symtab)\r
496                 return 0;\r
497         \r
498         nbuckets = pBuckets[0];\r
499         iSymCount = pBuckets[1];\r
500         pBuckets = &pBuckets[2];\r
501         pChains = &pBuckets[ nbuckets ];\r
502         \r
503         // Get hash\r
504         iNameHash = Elf_Int_HashString(Name);\r
505         iNameHash %= nbuckets;\r
506 \r
507         // Check Bucket\r
508         i = pBuckets[ iNameHash ];\r
509         if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {\r
510                 if(ret) *ret = symtab[ i ].value;\r
511                 return 1;\r
512         }\r
513         \r
514         // Walk Chain\r
515         while(pChains[i] != STN_UNDEF)\r
516         {\r
517                 i = pChains[i];\r
518                 if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {\r
519                         if(ret) *ret = symtab[ i ].value;\r
520                         return 1;\r
521                 }\r
522         }\r
523         return 0;\r
524 }\r
525 \r
526 /**\r
527  * \fn uint32_t Elf_Int_HashString(char *str)\r
528  * \brief Hash a string in the ELF format\r
529  * \param str   String to hash\r
530  * \return Hash value\r
531  */\r
532 uint32_t Elf_Int_HashString(char *str)\r
533 {\r
534         uint32_t        h = 0, g;\r
535         while(*str)\r
536         {\r
537                 h = (h << 4) + *str++;\r
538                 if( (g = h & 0xf0000000) )\r
539                         h ^= g >> 24;\r
540                 h &= ~g;\r
541         }\r
542         return h;\r
543 }\r

UCC git Repository :: git.ucc.asn.au