1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
46:
47: 48: 49: 50: 51: 52:
53:
54: #include <basic.h>
55: #include <errno.h>
56: #include <libstr.h>
57: #include <tk/tkernel.h>
58: #include <sys/debug.h>
59: #include <sys/segment.h>
60: #include <pagedef.h>
61: #include "pminfo.h"
62: #include "source.h"
63: #include "elf.h"
64:
65:
66: #if CPU_I386
67: #define LINK_ADDR 0x00100000
68: #endif
69:
70:
71: #if CPU_I386
72: # define CHK_ELFDATA(n) ( (n) == ELFDATA2LSB )
73: # define CHK_ELFMACH(n) ( (n) == EM_386 )
74: # define SHT_RELTYPE SHT_REL
75: #endif
76: #if CPU_SH3|CPU_SH4
77: # define CHK_ELFDATA(n) ( (n) == ELFDATA2LSB )
78: # define CHK_ELFMACH(n) ( (n) == EM_SH )
79: # define SHT_RELTYPE SHT_RELA
80: #endif
81: #if CPU_ARM
82: # define CHK_ELFDATA(n) ( (n) == ELFDATA2LSB )
83: # define CHK_ELFMACH(n) ( (n) == EM_ARM )
84: # define SHT_RELTYPE SHT_REL
85: #endif
86: #if CPU_MIPS
87: # define CHK_ELFDATA(n) ( (n) == ELFDATA2LSB )
88: # define CHK_ELFMACH(n) ( (n) == EM_MIPS )
89: # define SHT_RELTYPE SHT_REL
90: #endif
91: #if CPU_PPC
92: # define CHK_ELFDATA(n) ( (n) == ELFDATA2MSB )
93: # define CHK_ELFMACH(n) ( (n) == EM_PPC )
94: # define SHT_RELTYPE SHT_RELA
95: #endif
96:
97: 98: 99:
100: typedef struct {
101: B* text_ladr;
102: UW text_fofs;
103: UW text_size;
104: B* data_ladr;
105: UW data_fofs;
106: UW data_size;
107: B* bss_ladr;
108: UW bss_size;
109:
110: UH text_shndx;
111: UH data_shndx;
112: UH bss_shndx;
113: UW rel_text_fofs;
114: UW rel_text_size;
115: UW rel_data_fofs;
116: UW rel_data_size;
117:
118: UW symtbl_fofs;
119: UW symtbl_size;
120: BOOL vir_or_off; 121:
122: #if CPU_MIPS
123: UW reginf_fofs;
124: UW reginf_size;
125: W gp;
126: #endif
127: #if CPU_PPC
128: UW gp_info_fofs;
129: W gp;
130: #endif
131: } ELF_LoadInfo;
132:
133:
134: 135: 136:
137: LOCAL ER GetELFLoadInfoShdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, LoadSource *ldr )
138: {
139: Elf32_Shdr *shdr_buf, *shdr, *p;
140: W n;
141: B *adr;
142: W symsect = -1;
143: ER er;
144:
145: if ( hdr->e_shentsize < sizeof(Elf32_Shdr) || hdr->e_shnum == 0 )
146: { er = EX_INVAL; goto err_ret1; }
147:
148:
149: n = hdr->e_shentsize * hdr->e_shnum;
150: shdr_buf = Vmalloc(n);
151: if ( shdr_buf == NULL ) { er = EX_NOEXEC; goto err_ret1; }
152:
153:
154: er = ldr->read(ldr, hdr->e_shoff, shdr_buf, n);
155: if ( er < E_OK ) goto err_ret2;
156: if ( er < n ) { er = EX_NOEXEC; goto err_ret2; }
157:
158: for ( n = hdr->e_shnum, shdr = shdr_buf; --n >= 0;
159: shdr = (Elf32_Shdr*)((B*)shdr + hdr->e_shentsize) ) {
160:
161: switch ( shdr->sh_type ) {
162: case SHT_PROGBITS:
163: switch ( shdr->sh_flags ) {
164: case SHF_ALLOC|SHF_EXECINSTR:
165: if ( eli->text_size != 0 )
166: { er = EX_NOEXEC; goto err_ret2; }
167: eli->text_ladr = shdr->sh_addr;
168: eli->text_fofs = shdr->sh_offset;
169: eli->text_size = shdr->sh_size;
170: eli->text_shndx = shdr - shdr_buf;
171: break;
172: case SHF_ALLOC|SHF_WRITE:
173: if ( eli->data_ladr != NULL )
174: { er = EX_NOEXEC; goto err_ret2; }
175: eli->data_ladr = shdr->sh_addr;
176: eli->data_fofs = shdr->sh_offset;
177: eli->data_size = shdr->sh_size;
178: eli->data_shndx = shdr - shdr_buf;
179: break;
180: #if CPU_PPC
181: case SHF_WRITE:
182: if ( shdr->sh_size != 4 ) break;
183: if ( eli->gp_info_fofs != 0 )
184: { er = EX_NOEXEC; goto err_ret2; }
185: eli->gp_info_fofs = shdr->sh_offset;
186: break;
187: #endif
188: default:
189: if ( (shdr->sh_flags & SHF_ALLOC) == 0 )
190: continue;
191: er = EX_NOEXEC; goto err_ret2;
192: }
193: break;
194:
195: case SHT_NOBITS:
196: switch ( shdr->sh_flags ) {
197: case SHF_ALLOC|SHF_WRITE:
198: if ( eli->bss_ladr != NULL )
199: { er = EX_NOEXEC; goto err_ret2; }
200: eli->bss_ladr = shdr->sh_addr;
201: eli->bss_size = shdr->sh_size;
202: eli->bss_shndx = shdr - shdr_buf;
203: break;
204: case 0:
205: continue;
206: default:
207: er = EX_NOEXEC; goto err_ret2;
208: }
209: break;
210:
211: case SHT_RELTYPE:
212: if ( shdr->sh_info >= hdr->e_shnum
213: || shdr->sh_link >= hdr->e_shnum )
214: { er = EX_NOEXEC; goto err_ret2; }
215:
216:
217: p = &shdr_buf[shdr->sh_info];
218: if ( p->sh_type != SHT_PROGBITS )
219: continue;
220:
221: switch ( p->sh_flags ) {
222: case SHF_ALLOC|SHF_EXECINSTR:
223: if ( eli->rel_text_size != 0 )
224: { er = EX_NOEXEC; goto err_ret2; }
225: eli->rel_text_fofs = shdr->sh_offset;
226: eli->rel_text_size = shdr->sh_size;
227: break;
228: case SHF_ALLOC|SHF_WRITE:
229: if ( eli->rel_data_size != 0 )
230: { er = EX_NOEXEC; goto err_ret2; }
231: eli->rel_data_fofs = shdr->sh_offset;
232: eli->rel_data_size = shdr->sh_size;
233: break;
234: case 0:
235: continue;
236: default:
237: er = EX_NOEXEC; goto err_ret2;
238: }
239:
240: if ( symsect >= 0 && shdr->sh_link != (UW)symsect )
241: { er = EX_NOEXEC; goto err_ret2; }
242: symsect = shdr->sh_link;
243: break;
244: #if CPU_MIPS
245: case SHT_MIPS_REGINFO:
246: if( eli->reginf_size != 0 )
247: { er = EX_NOEXEC; goto err_ret2; }
248: eli->reginf_fofs = shdr->sh_offset;
249: eli->reginf_size = shdr->sh_size;
250: break;
251: #endif
252: default:
253: continue;
254: }
255: }
256:
257:
258: if ( eli->text_size == 0 ) { er = EX_NOEXEC; goto err_ret2; }
259: adr = PageAlignU(eli->text_ladr + eli->text_size);
260: if ( eli->data_ladr != adr ) { er = EX_NOEXEC; goto err_ret2; }
261: adr += eli->data_size;
262: if ( eli->bss_ladr < adr ) { er = EX_NOEXEC; goto err_ret2; }
263:
264: if ( symsect >= 0 ) {
265:
266: if ( shdr_buf[symsect].sh_type != SHT_SYMTAB )
267: { er = EX_NOEXEC; goto err_ret2; }
268: eli->symtbl_fofs = shdr_buf[symsect].sh_offset;
269: eli->symtbl_size = shdr_buf[symsect].sh_size;
270: }
271:
272: Vfree(shdr_buf);
273:
274: return E_OK;
275:
276: err_ret2:
277: Vfree(shdr_buf);
278: err_ret1:
279: TM_DEBUG_PRINT(("GetELFLoadInfoShdr ercd = %d\n", er));
280: return er;
281: }
282:
283: 284: 285:
286: LOCAL BOOL HasDynSeg( Elf32_Ehdr *hdr, LoadSource *ldr )
287: {
288: Elf32_Phdr *phdr_buf, *phdr;
289: W n;
290: ER er;
291:
292: if ( hdr->e_phentsize < sizeof(Elf32_Phdr) || hdr->e_phnum < 1 )
293: { er = EX_NOEXEC; goto err_ret1; }
294:
295:
296: n = hdr->e_phentsize * hdr->e_phnum;
297: phdr_buf = Vmalloc(n);
298: if ( phdr_buf == NULL ) { er = EX_NOMEM; goto err_ret1; }
299:
300:
301: er = ldr->read(ldr, hdr->e_phoff, phdr_buf, n);
302: if ( er < E_OK ) goto err_ret2;
303: if ( er < n ) { er = EX_NOEXEC; goto err_ret2; }
304:
305: for ( n = hdr->e_phnum, phdr = phdr_buf; --n >= 0;
306: phdr = (Elf32_Phdr*)((B*)phdr + hdr->e_phentsize) ) {
307:
308: if ( phdr->p_type == PT_DYNAMIC )
309: goto found;
310: }
311:
312: Vfree(phdr_buf);
313: return FALSE;
314:
315: found:
316: Vfree(phdr_buf);
317: return TRUE;
318:
319: err_ret2:
320: Vfree(phdr_buf);
321: err_ret1:
322: TM_DEBUG_PRINT(("HasDynSeg ercd = %d\n", er));
323: return FALSE;
324: }
325:
326: 327: 328:
329: LOCAL BOOL HasRelSec( Elf32_Ehdr *hdr, LoadSource *ldr )
330: {
331: Elf32_Shdr *shdr_buf, *shdr;
332: W n;
333: ER er;
334:
335: if ( hdr->e_shentsize < sizeof(Elf32_Shdr) || hdr->e_shnum == 0 )
336: { er = EX_NOEXEC; goto err_ret1; }
337:
338:
339: n = hdr->e_shentsize * hdr->e_shnum;
340: shdr_buf = Vmalloc(n);
341: if ( shdr_buf == NULL ) { er = EX_NOMEM; goto err_ret1; }
342:
343:
344: er = ldr->read(ldr, hdr->e_shoff, shdr_buf, n);
345: if ( er < E_OK ) goto err_ret2;
346: if ( er < n ) { er = EX_NOEXEC; goto err_ret2; }
347:
348: for ( n = hdr->e_shnum, shdr = shdr_buf; --n >= 0;
349: shdr = (Elf32_Shdr*)((B*)shdr + hdr->e_shentsize) ) {
350:
351: switch ( shdr->sh_type ) {
352: case SHT_RELTYPE:
353: goto found;
354: default:
355: continue;
356: }
357: }
358: Vfree(shdr_buf);
359: return FALSE;
360:
361: found:
362: Vfree(shdr_buf);
363: return TRUE;
364:
365: err_ret2:
366: Vfree(shdr_buf);
367: err_ret1:
368: TM_DEBUG_PRINT(("HasRelSec ercd = %d\n", er));
369: return FALSE;
370: }
371:
372: 373: 374:
375: LOCAL ER GetELFLoadInfoPhdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, LoadSource *ldr )
376: {
377: Elf32_Phdr *phdr_buf, *phdr;
378: W n;
379: B *adr;
380: ER er;
381:
382: if ( hdr->e_phentsize < sizeof(Elf32_Phdr) || hdr->e_phnum < 2 )
383: { er = EX_NOEXEC; goto err_ret1; }
384:
385:
386: n = hdr->e_phentsize * hdr->e_phnum;
387: phdr_buf = Vmalloc(n);
388: if ( phdr_buf == NULL ) { er = EX_NOMEM; goto err_ret1; }
389:
390:
391: er = ldr->read(ldr, hdr->e_phoff, phdr_buf, n);
392: if ( er < E_OK ) goto err_ret2;
393: if ( er < n ) { er = EX_NOEXEC; goto err_ret2; }
394:
395: for ( n = hdr->e_phnum, phdr = phdr_buf; --n >= 0;
396: phdr = (Elf32_Phdr*)((B*)phdr + hdr->e_phentsize) ) {
397:
398:
399: if ( phdr->p_type != PT_LOAD ) continue;
400:
401: switch ( phdr->p_flags ) {
402: case PF_R|PF_X:
403: if ( eli->text_size != 0 )
404: { er = EX_NOEXEC; goto err_ret2; }
405: eli->text_ladr = phdr->p_vaddr;
406: eli->text_fofs = phdr->p_offset;
407: eli->text_size = phdr->p_filesz;
408: break;
409:
410: case PF_R|PF_W:
411: case PF_R|PF_W|PF_X:
412: if ( eli->data_ladr != NULL )
413: { er = EX_NOEXEC; goto err_ret2; }
414: eli->data_ladr = phdr->p_vaddr;
415: eli->data_fofs = phdr->p_offset;
416: eli->data_size = phdr->p_filesz;
417: eli->bss_ladr = (B*)phdr->p_vaddr + phdr->p_filesz;
418: eli->bss_size = phdr->p_memsz - phdr->p_filesz;
419: break;
420:
421: case 0:
422: if ( phdr->p_filesz > 0 || phdr->p_memsz > 0 )
423: { er = EX_NOEXEC; goto err_ret2; }
424: continue;
425:
426: default:
427: er = EX_NOEXEC; goto err_ret2;
428: }
429: }
430:
431:
432: if ( eli->text_size == 0 || eli->data_ladr == NULL )
433: { er = EX_NOEXEC; goto err_ret2; }
434: adr = eli->text_ladr + eli->text_size;
435: if ( eli->data_ladr < (B*)PageAlignU(adr) )
436: { er = EX_NOEXEC; goto err_ret2; }
437:
438: Vfree(phdr_buf);
439:
440: return E_OK;
441:
442: err_ret2:
443: Vfree(phdr_buf);
444: err_ret1:
445: TM_DEBUG_PRINT(("GetELFLoadInfoPhdr ercd = %d\n", er));
446: return er;
447: }
448:
449: 450: 451:
452: LOCAL ER GetELFLoadInfo( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, LoadSource *ldr, BOOL relsec )
453: {
454: ER er;
455:
456: memset(eli, 0, sizeof(ELF_LoadInfo));
457:
458:
459: if ( !(hdr->e_ident[EI_CLASS] == ELFCLASS32
460: && CHK_ELFDATA(hdr->e_ident[EI_DATA])
461: && hdr->e_ident[EI_VERSION] == 1
462: && CHK_ELFMACH(hdr->e_machine)
463: && hdr->e_version == EV_CURRENT) ) {
464: er = EX_NOEXEC; goto err_ret;
465: }
466:
467: switch ( hdr->e_type ) {
468: case ET_EXEC:
469: if ( relsec ) {
470:
471: eli->vir_or_off = TRUE;
472: er = GetELFLoadInfoShdr(eli, hdr, ldr);
473: } else {
474:
475: er = GetELFLoadInfoPhdr(eli, hdr, ldr);
476: }
477: if ( er < E_OK ) goto err_ret;
478: break;
479:
480: case ET_DYN:
481:
482: er = GetELFLoadInfoPhdr(eli, hdr, ldr);
483: if ( er < E_OK ) goto err_ret;
484: break;
485:
486: case ET_REL:
487:
488: er = GetELFLoadInfoShdr(eli, hdr, ldr);
489: if ( er < E_OK ) goto err_ret;
490: break;
491:
492: default:
493: er = EX_NOEXEC; goto err_ret;
494: }
495:
496: return E_OK;
497:
498: err_ret:
499: TM_DEBUG_PRINT(("GetELFLoadInfo ercd = %d\n", er));
500: return er;
501: }
502:
503: #if CPU_MIPS
504: typedef struct {
505: W *addr;
506: UW val;
507: } Ahi_Info;
508: #define AHI_INFO_UNIT 1
509: #endif
510:
511: 512: 513:
514: LOCAL ER reloc1( ELF_LoadInfo *eli, LoadSource *ldr, W rtbl, W rtblsz, W lofs,
515: B *sect, W sectsz, Elf32_Sym *symtbl, W syment )
516: {
517: #if SHT_RELTYPE == SHT_REL
518: Elf32_Rel *reloc, *rp, *reloc_end;
519: #endif
520: #if SHT_RELTYPE == SHT_RELA
521: Elf32_Rela *reloc, *rp, *reloc_end;
522: #endif
523: #if CPU_ARM
524: W ofs;
525: #endif
526: #if CPU_MIPS
527: Ahi_Info *ahi_info = NULL;
528: Ahi_Info *ahi_infotmp;
529: W ahi_infomax = AHI_INFO_UNIT;
530: W ahi_infonext = 0;
531: W ahi_infoused = 0;
532: W ind;
533: W ahl, addend, nadr;
534: UH *hp;
535: #endif
536: W *wp, sv, i;
537: B *ladr;
538: ER er;
539:
540: if ( rtblsz == 0 ) return E_OK;
541:
542:
543: reloc = Vmalloc(rtblsz);
544: if ( reloc == NULL ) { er = EX_NOMEM; goto err_ret1; }
545: er = ldr->read(ldr, rtbl, reloc, rtblsz);
546: if ( er < E_OK ) goto err_ret2;
547: if ( er < rtblsz ) { er = EX_NOEXEC; goto err_ret2; }
548:
549: reloc_end = &reloc[rtblsz / sizeof(*reloc)];
550: if ( eli->vir_or_off ) {
551: for ( rp = reloc; rp < reloc_end; rp++ ) {
552:
553: rp->r_offset -= ((UW)sect - lofs);
554: }
555: }
556:
557: for ( rp = reloc; rp < reloc_end; rp++ ) {
558:
559: i = ELF32_R_SYM(rp->r_info);
560: if ( i >= syment || (UW)rp->r_offset >= (UW)sectsz )
561: { er = EX_NOEXEC; goto err_ret2; }
562:
563:
564: if ( ELF32_R_TYPE(rp->r_info) == 0 ) continue;
565:
566:
567: wp = (W*)(sect + (UW)rp->r_offset);
568: sv = (W)symtbl[i].st_value;
569:
570:
571: if ( symtbl[i].st_shndx == eli->text_shndx ) {
572: ladr = eli->text_ladr;
573: } else if ( symtbl[i].st_shndx == eli->data_shndx ) {
574: ladr = eli->data_ladr;
575: } else if ( symtbl[i].st_shndx == eli->bss_shndx ) {
576: ladr = eli->bss_ladr;
577: } else if ( symtbl[i].st_shndx == SHN_ABS ) {
578: ladr = (B*)0 - lofs;
579: } else if ( symtbl[i].st_shndx == SHN_UNDEF ) {
580: if ( ELF32_ST_BIND(symtbl[i].st_info) == STB_WEAK )
581: continue;
582: #if 1
583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596:
597: if ( i == 0 ) {
598: ladr = (B*)0 - lofs;
599: sv = 0;
600: } else
601: #endif
602: { er = EX_NOEXEC; goto err_ret2; }
603: } else {
604: er = EX_NOEXEC; goto err_ret2;
605: }
606:
607: #if CPU_I386
608: 609: 610: 611: 612: 613: 614: 615: 616: 617:
618: if ( sv >= LINK_ADDR ) sv -= (W)ladr;
619: #endif
620:
621:
622: switch ( ELF32_R_TYPE(rp->r_info) ) {
623: #if CPU_I386
624: case R_386_32:
625: if ( eli->vir_or_off ) {
626: sv = 0;
627: *wp -= (W)ladr;
628: }
629: *wp += sv + (W)ladr + lofs;
630: break;
631:
632: case R_386_PC32:
633: if ( eli->vir_or_off ) {
634: break;
635: }
636: *wp += sv - (W)rp->r_offset;
637: break;
638: #endif
639: #if CPU_ARM
640: case R_ARM_PC24:
641: if ( eli->vir_or_off ) {
642: break;
643: }
644: ofs = (W)((UW)*wp << 8) >> 8;
645: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
646: ofs -= (W)rp->r_offset >> 2;
647: } else {
648: ofs += (sv - (W)rp->r_offset) >> 2;
649: }
650: *wp = (*wp & 0xff000000) | (ofs & 0x00ffffff);
651: break;
652:
653: case R_ARM_ABS32:
654: if ( eli->vir_or_off ) {
655: sv = 0;
656: *wp -= (W)ladr;
657: }
658: *wp += sv + (W)ladr + lofs;
659: break;
660: case R_ARM_THM_PC22:
661: if ( !eli->vir_or_off ) {
662: er = EX_NOEXEC; goto err_ret2;
663: }
664: break;
665: #endif
666: #if CPU_MIPS
667: case R_MIPS_32:
668: if ( eli->vir_or_off ) {
669: SetMisalignW((UB*)wp, GetMisalignW((UB*)wp) - sv);
670: sv -= (W)ladr;
671: }
672: SetMisalignW((UB*)wp, GetMisalignW((UB*)wp) + (W)ladr + sv + lofs);
673: break;
674:
675: case R_MIPS_26:
676: if ( eli->vir_or_off ) {
677: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
678: nadr = (((*wp & 0x03ffffff) << 2) - (W)ladr) >> 2;
679: *wp = ( *wp & 0xfc000000) | ( nadr & 0x03ffffff);
680: } else {
681: *wp &= 0xfc000000;
682: }
683: sv -= (W)ladr;
684: }
685: addend = *wp & 0x03ffffff;
686: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
687: nadr = (addend << 2) | (((W)ladr + (W)rp->r_offset) & 0xf0000000);
688: }else{
689: nadr = (W)((UW)addend << 6) >> 4;
690: }
691: nadr += (W)ladr + sv + lofs;
692: nadr >>= 2;
693: *wp = ( *wp & 0xfc000000) | ( nadr & 0x03ffffff);
694: break;
695:
696: case R_MIPS_HI16:
697: if ( ahi_info == NULL) {
698: ahi_info = Vmalloc( sizeof( Ahi_Info) * AHI_INFO_UNIT);
699: if ( ahi_info == NULL) { er = EX_NOMEM; goto err_ret2; }
700: }
701: if( ahi_infoused ) {
702: ahi_infonext = 0;
703: ahi_infoused = 0;
704: }
705: if( ahi_infomax <= ahi_infonext){
706: ahi_infotmp = Vrealloc( ahi_info, sizeof( Ahi_Info) * ( ahi_infomax + AHI_INFO_UNIT));
707: if ( ahi_infotmp == NULL ) { er = EX_NOMEM; goto err_ret2; }
708: ahi_info = ahi_infotmp;
709: ahi_infomax += AHI_INFO_UNIT;
710: }
711: ahi_info[ ahi_infonext].addr = wp;
712: ahi_info[ ahi_infonext].val = (UW)*wp << 16;
713: ahi_infonext++;
714: break;
715:
716: case R_MIPS_LO16:
717: if ( ahi_info == NULL) { err = EX_NOEXEC; goto err_ret2; }
718: if ( ahi_infoused == 0 ) {
719: ahi_infoused = 1;
720: for ( ind = 0; ind < ahi_infonext; ind++ ) {
721: ahl = ( ahi_info[ ind].val & 0xffff0000) + ( short)(*wp & 0xffff);
722: if ( eli->vir_or_off ) {
723: ahl -= sv;
724: sv -= (W)ladr;
725: }
726: nadr = ahl + (W)ladr + sv + lofs;
727: *ahi_info[ ind].addr = ((( nadr - (short)nadr) >> 16) & 0x0000ffff)
728: | ( *ahi_info[ ind].addr & 0xffff0000);
729: }
730: if ( 1 < ahi_infonext ) {
731: ahi_info[ 0] = ahi_info[ ahi_infonext - 1];
732: ahi_infonext = 1;
733: }
734: } else {
735: ahl = ( ahi_info[ 0].val & 0xffff0000) + ( short)(*wp & 0xffff);
736: if ( eli->vir_or_off ) {
737: ahl -= sv;
738: sv -= (W)ladr;
739: }
740: nadr = ahl + (W)ladr + sv + lofs;
741: }
742: *wp = ( nadr & 0xffff) | (*wp & 0xffff0000);
743: break;
744:
745: case R_MIPS_GPREL16:
746: case R_MIPS_LITERAL:
747: if ( eli->vir_or_off ) {
748: break;
749: }
750: addend = *wp & 0xffff;
751: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
752: nadr = ((W)ladr + (( sv + addend + eli->gp ) & 0x0000ffff) - eli->gp) & 0x0000ffff;
753: }else{
754: nadr = ((W)ladr + sv + addend - eli->gp ) & 0x0000ffff;
755: }
756: *wp = nadr | (*wp & 0xffff0000);
757: break;
758:
759: case R_MIPS16_26:
760: if ( !eli->vir_or_off ) {
761: er = EX_NOEXEC; goto err_ret2;
762: }
763:
764: hp = (UH*)wp;
765: addend = ((UW)(*hp & 0x03e0) << 13)
766: | ((UW)(*hp & 0x001f) << 23)
767: | ((UW)*(hp + 1) << 2);
768: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
769: addend -= (W)ladr;
770: } else {
771: addend = 0;
772: }
773: sv -= (W)ladr;
774:
775:
776: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
777: nadr = (addend << 2) | (((W)ladr + (W)rp->r_offset) & 0xf0000000);
778: }else{
779: nadr = (W)((UW)addend << 6) >> 4;
780: }
781: nadr += (W)ladr + sv + lofs;
782: nadr >>= 2;
783:
784: *hp = (*hp & 0xfc00)
785: | (( nadr & 0x03e00000) >> 21)
786: | (( nadr & 0x001f0000) >> 11);
787: *(hp+1) = nadr & 0xffff;
788: break;
789:
790: case R_MIPS16_GPREL:
791: if ( !eli->vir_or_off ) {
792: er = EX_NOEXEC; goto err_ret2;
793: }
794: break;
795:
796: #endif
797: #if CPU_SH3|CPU_SH4
798: case R_SH_DIR32:
799: if ( ELF32_ST_TYPE(symtbl[i].st_info) == STT_SECTION ){
800: *wp += rp->r_addend + lofs;
801: } else {
802: if ( eli->vir_or_off ) {
803: *wp -= sv;
804: sv -= (W)ladr;
805: }
806: *wp += sv + rp->r_addend + (W)ladr + lofs;
807: }
808: break;
809: case R_SH_REL32:
810: if ( !eli->vir_or_off ) {
811: er = EX_NOEXEC; goto err_ret2;
812: }
813: break;
814: #endif
815: #if CPU_PPC
816: case R_PPC_ADDR32:
817: if ( !eli->vir_or_off ) sv += (W)ladr;
818: *wp = sv + rp->r_addend + lofs;
819: break;
820: case R_PPC_ADDR16_LO:
821: if ( !eli->vir_or_off ) sv += (W)ladr;
822: *(H*)wp = sv + rp->r_addend + lofs;
823: break;
824: case R_PPC_ADDR16_HI:
825: if ( !eli->vir_or_off ) sv += (W)ladr;
826: *(H*)wp = (sv + rp->r_addend + lofs) >> 16;
827: break;
828: case R_PPC_ADDR16_HA:
829: if ( !eli->vir_or_off ) sv += (W)ladr;
830: sv += rp->r_addend + lofs;
831: *(H*)wp = (sv >> 16) - ((H)sv >> 15);
832: break;
833: case R_PPC_REL32:
834: if ( eli->vir_or_off ) break;
835: *wp = sv + rp->r_addend - (W)rp->r_offset;
836: break;
837: case R_PPC_REL24:
838: case R_PPC_PLTREL24:
839: if ( eli->vir_or_off ) break;
840: sv += rp->r_addend - (W)rp->r_offset;
841: if ( sv < -0x02000000 || sv > 0x01fffffc )
842: { er = EX_NOEXEC; goto err_ret2; }
843: *wp = (*wp & 0xfc000003) | (sv & 0x03fffffc);
844: break;
845: case R_PPC_REL14:
846: case R_PPC_REL14_BRTAKEN:
847: case R_PPC_REL14_BRNTAKEN:
848: if ( eli->vir_or_off ) break;
849: sv += rp->r_addend - (W)rp->r_offset;
850: if ( sv < -0x00008000 || sv > 0x00007ffc )
851: { er = EX_NOEXEC; goto err_ret2; }
852: *wp = (*wp & 0xffff0003) | (sv & 0x0000fffc);
853: switch ( ELF32_R_TYPE(rp->r_info) ) {
854: case R_PPC_REL14_BRTAKEN:
855: if ( sv >= 0 ) *wp |= 0x00200000;
856: else *wp &= ~0x00200000;
857: break;
858: case R_PPC_REL14_BRNTAKEN:
859: if ( sv >= 0 ) *wp &= ~0x00200000;
860: else *wp |= 0x00200000;
861: break;
862: }
863: break;
864: case R_PPC_SDAREL16:
865: if ( eli->vir_or_off ) break;
866: sv += rp->r_addend + (W)ladr - eli->gp;
867: if ( sv < -0x00008000 || sv > 0x00007fff )
868: { er = EX_NOEXEC; goto err_ret2; }
869: *(H*)wp = sv;
870: break;
871: #endif
872: default:
873: er = EX_NOEXEC; goto err_ret2;
874: }
875: }
876:
877: #if CPU_MIPS
878: if( ahi_info ) {
879: Vfree(ahi_info);
880: }
881: #endif
882: Vfree(reloc);
883:
884: return E_OK;
885:
886: err_ret2:
887: #if CPU_MIPS
888: if( ahi_info ) {
889: Vfree(ahi_info);
890: }
891: #endif
892: Vfree(reloc);
893: err_ret1:
894: TM_DEBUG_PRINT(("reloc1 ercd = %d\n", er));
895: return er;
896: }
897:
898: #if CPU_MIPS
899: 900: 901:
902: LOCAL ER elf_get_gp( LoadSource *ldr, ELF_LoadInfo *eli )
903: {
904: ER er;
905: W n;
906: Elf32_RegInfo reginfo;
907:
908:
909: n = eli->reginf_size;
910: if( n <= 0 ) { er = EX_NOEXEC; goto err_ret; }
911:
912: er = ldr->read(ldr, eli->reginf_fofs, ®info, n);
913: if ( er < E_OK ) goto err_ret;
914: if ( er < n ) { er = EX_NOEXEC; goto err_ret; }
915:
916: eli->gp = reginfo.ri_gp_value;
917: return E_OK;
918:
919: err_ret:
920: TM_DEBUG_PRINT(("elf_get_gp ercd = %d\n", er));
921: return er;
922: }
923: #endif
924:
925: #if CPU_PPC
926: 927: 928:
929: LOCAL ER elf_get_gp( LoadSource* ldr, ELF_LoadInfo *eli )
930: {
931: UW gp_info;
932: ER er;
933:
934: if ( eli->gp_info_fofs == 0 ) { er = EX_NOEXEC; goto err_ret; }
935:
936:
937: er = ldr->read(ldr, eli->gp_info_fofs, (B*)&gp_info, sizeof(gp_info));
938: if ( er < E_OK ) goto err_ret;
939: if ( er < sizeof(gp_info) ) { er = EX_NOEXEC; goto err_ret; }
940:
941: eli->gp = gp_info;
942:
943: return E_OK;
944:
945: err_ret:
946: TM_DEBUG_PRINT(("elf_get_gp ercd = %d \n", er));
947: return er;
948: }
949: #endif
950:
951: 952: 953:
954: LOCAL ER elf_relocation( ProgInfo *pg, LoadSource *ldr, ELF_LoadInfo *eli, W lofs )
955: {
956: Elf32_Sym *symtbl;
957: W n;
958: ER er;
959:
960: if ( eli->symtbl_size == 0 )
961: return E_OK;
962:
963:
964: n = eli->symtbl_size;
965: symtbl = Vmalloc(n);
966: if ( symtbl == NULL ) { er = EX_NOMEM; goto err_ret1; }
967: er = ldr->read(ldr, eli->symtbl_fofs, symtbl, n);
968: if ( er < E_OK ) goto err_ret2;
969: if ( er < n ) { er = EX_NOEXEC; goto err_ret2; }
970:
971: n /= sizeof(Elf32_Sym);
972:
973: #if CPU_MIPS|CPU_PPC
974: er = elf_get_gp(ldr, eli);
975: if ( er < E_OK ) goto err_ret2;
976: #endif
977:
978:
979: er = reloc1(eli, ldr, eli->rel_text_fofs, eli->rel_text_size, lofs,
980: eli->text_ladr + lofs, eli->text_size, symtbl, n);
981: if ( er < E_OK ) goto err_ret2;
982:
983:
984: er = reloc1(eli, ldr, eli->rel_data_fofs, eli->rel_data_size, lofs,
985: eli->data_ladr + lofs, eli->data_size, symtbl, n);
986: if ( er < E_OK ) goto err_ret2;
987:
988: Vfree(symtbl);
989:
990: return E_OK;
991:
992: err_ret2:
993: Vfree(symtbl);
994: err_ret1:
995: TM_DEBUG_PRINT(("elf_relocation ercd = %d\n", er));
996: return er;
997: }
998:
999: 1000: 1001:
1002: EXPORT ER elf_load( ProgInfo *pg, LoadSource *ldr, UINT attr, Elf32_Ehdr *hdr )
1003: {
1004: ELF_LoadInfo eli;
1005: B *ladr, *top_adr;
1006: UW npage;
1007: W lofs, sz;
1008: BOOL relsec;
1009: ER er;
1010:
1011: if ( hdr->e_type == ET_EXEC ) {
1012: relsec = (HasDynSeg(hdr, ldr) ? FALSE : HasRelSec(hdr, ldr));
1013: } else {
1014: relsec = FALSE;
1015: }
1016:
1017:
1018: if ( hdr->e_type == ET_DYN )
1019: { er = EX_NOEXEC; goto err_ret1; }
1020:
1021:
1022: er = GetELFLoadInfo(&eli, hdr, ldr, relsec);
1023: if ( er < E_OK ) goto err_ret1;
1024:
1025: top_adr = PageAlignL(eli.text_ladr);
1026:
1027:
1028: npage = PageCount(eli.bss_ladr + eli.bss_size - top_adr);
1029:
1030: ladr = top_adr;
1031: if ( hdr->e_type != ET_EXEC
1032: || (hdr->e_type == ET_EXEC && eli.vir_or_off) ) {
1033:
1034:
1035: er = tk_get_smb((void**)&ladr, npage, attr);
1036: if ( er < E_OK ) { er = EX_NOMEM; goto err_ret1; }
1037: }
1038:
1039: pg->loadadr = ladr;
1040: pg->loadsz = eli.bss_ladr + eli.bss_size - top_adr;
1041:
1042: lofs = ladr - top_adr;
1043:
1044:
1045: er = ldr->read(ldr, eli.text_fofs, eli.text_ladr + lofs, eli.text_size);
1046: if ( er < E_OK ) goto err_ret2;
1047: if ( er < eli.text_size ) { er = EX_NOEXEC; goto err_ret2; }
1048:
1049:
1050: er = ldr->read(ldr, eli.data_fofs, eli.data_ladr + lofs, eli.data_size);
1051: if ( er < E_OK ) goto err_ret2;
1052: if ( er < eli.data_size ) { er = EX_NOEXEC; goto err_ret2; }
1053:
1054: if ( hdr->e_type == ET_REL
1055: || ( hdr->e_type == ET_EXEC && eli.vir_or_off) ) {
1056:
1057: er = elf_relocation(pg, ldr, &eli, lofs);
1058: if ( er < E_OK ) goto err_ret2;
1059: }
1060:
1061:
1062: sz = eli.text_ladr + eli.text_size - top_adr;
1063: er = SetMemoryAccess(ladr, sz, MM_READ|MM_EXECUTE);
1064: if ( er < 0 ) goto err_ret2;
1065:
1066: 1067:
1068: FlushMemCache(ladr, sz, TCM_ICACHE|TCM_DCACHE);
1069: FlushMemCache(eli.data_ladr + lofs, eli.data_size, TCM_ICACHE|TCM_DCACHE);
1070:
1071:
1072: pg->entry = (FP)((B*)hdr->e_entry + lofs);
1073: pg->modentry = NULL;
1074:
1075: return E_OK;
1076:
1077: err_ret2:
1078: if ( hdr->e_type != ET_EXEC
1079: || ( hdr->e_type == ET_EXEC && eli.vir_or_off) ) {
1080: tk_rel_smb(ladr);
1081: }
1082: err_ret1:
1083: TM_DEBUG_PRINT(("elf_load ercd = %d\n", er));
1084: return er;
1085: }