📄 ldelf.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel / Standard Extension * * Copyright (C) 2006 by Ken Sakamura. All rights reserved. * T-Kernel / Standard Extension is distributed * under the T-License for T-Kernel / Standard Extension. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/11. * *---------------------------------------------------------------------- *//* * ldelf.c (memory) * * ELF format program loading (MC9328 Virtual storage version) * * Supports the following loading formats: * * On-demand loading * * Global loading/not relocated * * Global loading/relocated */#include "segmgr.h"#include <cnvend.h>#ifdef DEBUG# define _ER_REC(n) ( E_REC | (n) )#else# define _ER_REC(n) ( E_REC )#endif#define LINK_ADDR 0x00100000 /* Link address */#define TSD_RL1_MSK_2 2#define TSD_GEI_SYM_M1 (-1)#define TSD_RL1_MSK_0XFF000000 0xff000000U#define TSD_RL1_MSK_0X00FFFFFF 0x00ffffffU#define TSD_GEI_VAL_2 2#define TSD_RL1_SFT_8 8#define TSD_DLE_POS_0 0#define TSD_DLE_POS_1 1#define TSD_LDE_ERR_1 1#define TSD_LDE_ERR_2 2#define TSD_LDE_ERR_3 3#define TSD_LDE_ERR_4 4#define TSD_LDE_ERR_5 5#define TSD_LDE_ERR_6 6#define TSD_LDE_ERR_7 7#define TSD_LDE_ERR_8 8#define TSD_LDE_ERR_9 9#define TSD_LDE_ERR_10 10#define TSD_LDE_ERR_11 11#define TSD_LDE_ERR_12 12#define TSD_LDE_ERR_13 13#define TSD_LDE_ERR_14 14#define TSD_LDE_ERR_15 15#define TSD_LDE_ERR_16 16#define TSD_LDE_ERR_17 17/* Format checking for each supported model */#define CHK_ELFDATA(n) ( (n) == ELFDATA2LSB )#define CHK_ELFMACH(n) ( (n) == EM_ARM )/* * ELF loading information */typedef struct { VB* text_ladr; /* text area loading address */ UW text_fofs; /* text area file position */ UW text_size; /* text area size */ VB* data_ladr; /* data area loading address */ UW data_fofs; /* data area file position */ UW data_size; /* data area size */ VB* bss_ladr; /* bss area first address */ UW bss_size; /* bss area size */ UW stack_size; /* Stack size */ UH text_shndx; /* text area section number */ UH data_shndx; /* data area section number */ UH bss_shndx; /* bss area section number */ UW rel_text_fofs; /* File position of text area relocation information */ UW rel_text_size; /* Size of text area relocation information */ UW rel_data_fofs; /* File position of data area relocation information */ UW rel_data_size; /* Size of data area relocation information */ UW symtbl_fofs; /* File position of symbol table */ UW symtbl_size; /* Size of symbol table */ BOOL vir_or_off; /* Virtual address (TRUE) or offset (FALSE) */} ELF_LoadInfo;LOCAL ER CheckLoadAddress( ELF_LoadInfo *eli );LOCAL ER CheckSysLoadAddress( ELF_LoadInfo *eli );LOCAL ER GetELFLoadInfoShdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr );LOCAL BOOL HasDynSeg( Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr );LOCAL BOOL HasRelSec( Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr );LOCAL ER GetELFLoadInfoPhdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr );LOCAL ER GetELFLoadInfo( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr, BOOL relsec );LOCAL ER reloc1( ELF_LoadInfo *eli, POBJ_HDR *pohdr, W rtbl, W rtblsz, W lofs, VB *sect, W sectsz, Elf32_Sym *symtbl, W syment, BzRead *bzr );LOCAL ER elf_relocation( LDINFO *li, ELF_LoadInfo *eli, W lofs, BzRead *bzr );#ifdef DEBUGLOCAL void prELFLoadInfo( ELF_LoadInfo *eli ){ DEBUG_PRINT(("ELF_LoadInfo\n")); DEBUG_PRINT(("\t.text_ladr = 0x%08x\n", eli->text_ladr)); DEBUG_PRINT(("\t.text_fofs = 0x%08x\n", eli->text_fofs)); DEBUG_PRINT(("\t.text_size = 0x%08x\n", eli->text_size)); DEBUG_PRINT(("\t.data_ladr = 0x%08x\n", eli->data_ladr)); DEBUG_PRINT(("\t.data_fofs = 0x%08x\n", eli->data_fofs)); DEBUG_PRINT(("\t.data_size = 0x%08x\n", eli->data_size)); DEBUG_PRINT(("\t.bss_ladr = 0x%08x\n", eli->bss_ladr)); DEBUG_PRINT(("\t.bss_size = 0x%08x\n", eli->bss_size)); DEBUG_PRINT(("\t.stack_size = %d\n", eli->stack_size)); DEBUG_PRINT(("\t.text_shndx = %d\n", eli->text_shndx)); DEBUG_PRINT(("\t.data_shndx = %d\n", eli->data_shndx)); DEBUG_PRINT(("\t.bss_shndx = %d\n", eli->bss_shndx)); DEBUG_PRINT(("\t.rel_text_fofs = 0x%08x\n", eli->rel_text_fofs)); DEBUG_PRINT(("\t.rel_text_size = %d\n", eli->rel_text_size)); DEBUG_PRINT(("\t.rel_data_fofs = 0x%08x\n", eli->rel_data_fofs)); DEBUG_PRINT(("\t.rel_data_size = %d\n", eli->rel_data_size)); DEBUG_PRINT(("\t.symtbl_fofs = 0x%08x\n", eli->symtbl_fofs)); DEBUG_PRINT(("\t.symtbl_size = %d\n", eli->symtbl_size));}#endif/* * Check if the loading address is within a range of the process unique space. */LOCAL ER CheckLoadAddress( ELF_LoadInfo *eli ){ ER err; if ( !isLocalSpace(eli->text_ladr) || !isLocalSpace(eli->bss_ladr + eli->bss_size) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("CheckLoadAddress err = %d (%d)\n", err, (UH)err)); return err;}/* * Check if the loading address is within a range of system program loading. */LOCAL ER CheckSysLoadAddress( ELF_LoadInfo *eli ){ ER err; if ( !isSysLoadSpace(eli->text_ladr) || !isSysLoadSpace(eli->bss_ladr + eli->bss_size) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret; } return E_OK;err_ret: DEBUG_PRINT(("CheckSysLoadAddress err = %d (%d)\n", err, (UH)err)); return err;}/* * Obtain loading information from ELF section header. */LOCAL ER GetELFLoadInfoShdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr ){ Elf32_Shdr *shdr_buf, *shdr, *p; W n; VB *adr; W symsect = TSD_GEI_SYM_M1; ER err; if ( (hdr->e_shentsize < sizeof(Elf32_Shdr)) || (hdr->e_shnum == 0) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret1; } /* Buffer for loading section header */ n = hdr->e_shentsize * hdr->e_shnum; shdr_buf = Vmalloc((size_t)n); if ( shdr_buf == NULL ) { err = E_NOMEM; goto err_ret1; } /* Load section header */ err = ReadProgFile(pohdr, (W)hdr->e_shoff, (VB*)shdr_buf, n, bzr); if ( err < E_OK ) { goto err_ret2; } eli->stack_size = (UW)DefaultStackSize; for ( n = (W)hdr->e_shnum, shdr = shdr_buf; --n >= 0; shdr = (Elf32_Shdr*)((VB*)shdr + hdr->e_shentsize) ) { switch ( shdr->sh_type ) { case SHT_PROGBITS: if (( shdr->sh_flags & SHF_ALLOC) == 0U) { continue; /* Ignore */ } switch ( shdr->sh_flags ) { case SHF_ALLOC|SHF_EXECINSTR: /* text area */ if ( eli->text_size != 0U ) { err = _ER_REC(TSD_LDE_ERR_2); goto err_ret2; } eli->text_ladr = shdr->sh_addr; eli->text_fofs = shdr->sh_offset; eli->text_size = shdr->sh_size; eli->text_shndx = (UH)(shdr - shdr_buf); break; case SHF_ALLOC|SHF_WRITE: /* data area */ if ( eli->data_ladr != NULL ) { err = _ER_REC(TSD_LDE_ERR_3); goto err_ret2; } eli->data_ladr = shdr->sh_addr; eli->data_fofs = shdr->sh_offset; eli->data_size = shdr->sh_size; eli->data_shndx = (UH)(shdr - shdr_buf); break; default: err = _ER_REC(TSD_LDE_ERR_4); goto err_ret2; } break; case SHT_NOBITS: switch ( shdr->sh_flags ) { case SHF_ALLOC|SHF_WRITE: /* bss area */ if ( eli->bss_ladr != NULL ) { err = _ER_REC(TSD_LDE_ERR_5); goto err_ret2; } eli->bss_ladr = shdr->sh_addr; eli->bss_size = shdr->sh_size; eli->bss_shndx = (UH)(shdr - shdr_buf); break; case SHF_ALLOC: /* stack area */ eli->stack_size = shdr->sh_size; break; case 0: continue; /* Ignore */ default: err = _ER_REC(TSD_LDE_ERR_6); goto err_ret2; } break; case SHT_REL: if ( (shdr->sh_info >= hdr->e_shnum) || (shdr->sh_link >= hdr->e_shnum) ) { err = _ER_REC(TSD_LDE_ERR_7); goto err_ret2; } /* Section to be relocated */ p = &shdr_buf[shdr->sh_info]; if ( p->sh_type != SHT_PROGBITS ) { continue; } switch ( p->sh_flags ) { case SHF_ALLOC|SHF_EXECINSTR: /* text area */ if ( eli->rel_text_size != 0U ) { err = _ER_REC(TSD_LDE_ERR_9); goto err_ret2; } eli->rel_text_fofs = shdr->sh_offset; eli->rel_text_size = shdr->sh_size; break; case SHF_ALLOC|SHF_WRITE: /* data area */ if ( eli->rel_data_size != 0U ) { err = _ER_REC(TSD_LDE_ERR_10); goto err_ret2; } eli->rel_data_fofs = shdr->sh_offset; eli->rel_data_size = shdr->sh_size; break; case 0: continue; /* Ignore */ default: err = _ER_REC(TSD_LDE_ERR_11); goto err_ret2; } if ( (symsect >= 0) && (shdr->sh_link != (UW)symsect) ) { err = _ER_REC(TSD_LDE_ERR_12); goto err_ret2; } symsect = (W)shdr->sh_link; break; default: continue; /* Ignore */ } } /* Check validity */ if ( eli->text_size == 0U ) { err = _ER_REC(TSD_LDE_ERR_13); goto err_ret2; } adr = PageAlignU(eli->text_ladr + eli->text_size); if ( eli->data_ladr != adr ) { err = _ER_REC(TSD_LDE_ERR_14); goto err_ret2; } adr += eli->data_size; if ( eli->bss_ladr < adr ) { err = _ER_REC(TSD_LDE_ERR_15); goto err_ret2; } if ( symsect >= 0 ) { /* Symbol table for relocation */ if ( shdr_buf[symsect].sh_type != SHT_SYMTAB ) { err = _ER_REC(TSD_LDE_ERR_16); goto err_ret2; } eli->symtbl_fofs = shdr_buf[symsect].sh_offset; eli->symtbl_size = shdr_buf[symsect].sh_size; } Vfree(shdr_buf); return E_OK;err_ret2: Vfree(shdr_buf);err_ret1: DEBUG_PRINT(("GetELFLoadInfoShdr err = %d (%d)\n", err, (UH)err)); return err;}/* * Obtain loading information from ELF program header */LOCAL BOOL HasDynSeg( Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr ){ Elf32_Phdr *phdr_buf, *phdr; W n; ER err; if ( (hdr->e_phentsize < sizeof(Elf32_Phdr)) || (hdr->e_phnum < 1) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret1; } n = hdr->e_phentsize * hdr->e_phnum; phdr_buf = Vmalloc((size_t)n); if ( phdr_buf == NULL ) { err = E_NOMEM; goto err_ret1; } /* Load program header */ err = ReadProgFile(pohdr, (W)hdr->e_phoff, (VB*)phdr_buf, n, bzr); if ( err < E_OK ) { goto err_ret2; } for ( n = (W)hdr->e_phnum, phdr = phdr_buf; --n >= 0; phdr = (Elf32_Phdr*)((VB*)phdr + hdr->e_phentsize) ) { if ( phdr->p_type == PT_DYNAMIC ) { goto found; } } Vfree(phdr_buf); return FALSE;found: Vfree(phdr_buf); return TRUE;err_ret2: Vfree(phdr_buf);err_ret1: DEBUG_PRINT(("HasDynSeg err = %d (%d)\n", err, (UH)err)); return FALSE;}/* * Relocation section check */LOCAL BOOL HasRelSec( Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr ){ Elf32_Shdr *shdr_buf, *shdr; W n; ER err; if ( (hdr->e_shentsize < sizeof(Elf32_Shdr)) || (hdr->e_shnum == 0) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret1; } n = hdr->e_shentsize * hdr->e_shnum; shdr_buf = Vmalloc((size_t)n); if ( shdr_buf == NULL ) { err = E_NOMEM; goto err_ret1; } /* Load section header */ err = ReadProgFile(pohdr, (W)hdr->e_shoff, (VB*)shdr_buf, n, bzr); if ( err < E_OK ) { goto err_ret2; } for ( n = (W)hdr->e_shnum, shdr = shdr_buf; --n >= 0; shdr = (Elf32_Shdr*)((VB*)shdr + hdr->e_shentsize) ) { switch ( shdr->sh_type ) { case SHT_REL: goto found; default: continue; /* Ignore */ } } Vfree(shdr_buf); return FALSE;found: Vfree(shdr_buf); return TRUE;err_ret2: Vfree(shdr_buf);err_ret1: DEBUG_PRINT(("HasRelSec err = %d (%d)\n", err, (UH)err)); return FALSE;}/* * Obtain loading information from ELF program header */LOCAL ER GetELFLoadInfoPhdr( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr ){ Elf32_Phdr *phdr_buf, *phdr; W n; VB *adr; ER err; if ( (hdr->e_phentsize < sizeof(Elf32_Phdr)) || (hdr->e_phnum < TSD_GEI_VAL_2) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret1; } /* Buffer for loading program header */ n = hdr->e_phentsize * hdr->e_phnum; phdr_buf = Vmalloc((size_t)n); if ( phdr_buf == NULL ) { err = E_NOMEM; goto err_ret1; } /* Load program header */ err = ReadProgFile(pohdr, (W)hdr->e_phoff, (VB*)phdr_buf, n, bzr); if ( err < E_OK ) { goto err_ret2; } eli->stack_size = (UW)DefaultStackSize; for ( n = (W)hdr->e_phnum, phdr = phdr_buf; --n >= 0; phdr = (Elf32_Phdr*)((VB*)phdr + hdr->e_phentsize) ) { /* Ignore non-loadable segments */ if ( phdr->p_type != (UW)PT_LOAD ) { continue; } switch ( phdr->p_flags ) { case PF_R|PF_X: /* text area */ if ( eli->text_size != 0U ) { err = _ER_REC(TSD_LDE_ERR_2); goto err_ret2; } eli->text_ladr = phdr->p_vaddr; eli->text_fofs = phdr->p_offset; eli->text_size = phdr->p_filesz; break; case PF_R|PF_W: /* data, bss area */ if ( eli->data_ladr != NULL ) { err = _ER_REC(TSD_LDE_ERR_3); goto err_ret2; } eli->data_ladr = phdr->p_vaddr; eli->data_fofs = phdr->p_offset; eli->data_size = phdr->p_filesz; eli->bss_ladr = (VB*)phdr->p_vaddr + phdr->p_filesz; eli->bss_size = phdr->p_memsz - phdr->p_filesz; break; case PF_R: /* stack area */ if ( phdr->p_filesz > 0U ) { err = _ER_REC(TSD_LDE_ERR_4); goto err_ret2; } eli->stack_size = phdr->p_memsz; break; case 0: if ( (phdr->p_filesz > 0U) || (phdr->p_memsz > 0U) ) { err = _ER_REC(TSD_LDE_ERR_5); goto err_ret2; } continue; /* Ignore */ default: err = _ER_REC(TSD_LDE_ERR_6); goto err_ret2; } } /* Check validity */ if ( (eli->text_size == 0U) || (eli->data_ladr == NULL) ) { err = _ER_REC(TSD_LDE_ERR_7); goto err_ret2; } adr = eli->text_ladr + eli->text_size; if ( eli->data_ladr < (VB*)PageAlignU(adr) ) { err = _ER_REC(TSD_LDE_ERR_8); goto err_ret2; } Vfree(phdr_buf); return E_OK;err_ret2: Vfree(phdr_buf);err_ret1: DEBUG_PRINT(("GetELFLoadInfoPhdr err = %d (%d)\n", err, (UH)err)); return err;}/* * Obtain ELF loading information */LOCAL ER GetELFLoadInfo( ELF_LoadInfo *eli, Elf32_Ehdr *hdr, POBJ_HDR *pohdr, BzRead *bzr, BOOL relsec ){ ER err; memset(eli, 0, (size_t)sizeof(ELF_LoadInfo)); /* Check header */ if ( !((hdr->e_ident[EI_CLASS] == ELFCLASS32) && CHK_ELFDATA(hdr->e_ident[EI_DATA]) && (hdr->e_ident[EI_VERSION] == 1U) && CHK_ELFMACH(hdr->e_machine) && (hdr->e_version == EV_CURRENT)) ) { err = _ER_REC(TSD_LDE_ERR_1); goto err_ret; } switch ( hdr->e_type ) { case ET_EXEC: if ( relsec != 0 ) { /* Section Header */ eli->vir_or_off = TRUE; err = GetELFLoadInfoShdr(eli, hdr, pohdr, bzr); } else { /* Program Header */ err = GetELFLoadInfoPhdr(eli, hdr, pohdr, bzr); } if ( err < E_OK ) { goto err_ret; } break; case ET_DYN: /* Obtain loading information from program header */ err = GetELFLoadInfoPhdr(eli, hdr, pohdr, bzr); if ( err < E_OK ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -