⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 binfmt_elf32.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
字号:
/* Copyright (C) 2005 David Decotigny   This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2   of the License, or (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,   USA. */#include <sos/kmalloc.h>#include <sos/assert.h>#include <sos/physmem.h>#include <drivers/bochs.h>#include <hwcore/paging.h>#include <drivers/zero.h>#include "binfmt_elf32.h"/** * The "C" structure of a user program image in the kernel. Structures * like this are created by the Makefile in the userland/ directory */struct userprog_entry{  const char *name;  sos_vaddr_t bottom_vaddr;  sos_vaddr_t top_vaddr;};/** * Symbol marking the start of the userprogs table, as setup by the * ld script in the userland/ directory */extern char _userprogs_table;/** * Structure of a mapped resource for an ELF32 program (ie a portion * of the kernel space) */struct elf32_mapped_program{  sos_vaddr_t vaddr;  sos_size_t  size;  int ref_cnt;  struct sos_umem_vmm_mapped_resource mr;};/** Called after the virtual region has been inserted inside its    address space */static void elf32prog_ref(struct sos_umem_vmm_vr * vr){  struct elf32_mapped_program * elf32prog_resource;  elf32prog_resource = (struct elf32_mapped_program*) sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;    elf32prog_resource->ref_cnt ++;}/** Called when the virtual region is removed from its address    space */static void elf32prog_unref(struct sos_umem_vmm_vr * vr){  struct elf32_mapped_program * elf32prog_resource;  elf32prog_resource    = (struct elf32_mapped_program*)      sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;    elf32prog_resource->ref_cnt --;  SOS_ASSERT_FATAL(elf32prog_resource->ref_cnt >= 0);  /* Free the resource if it becomes unused */  if (elf32prog_resource->ref_cnt == 0)    sos_kfree((sos_vaddr_t)elf32prog_resource);}/** Called when a legitimate page fault is occuring in the VR */static sos_ret_t elf32prog_page_in(struct sos_umem_vmm_vr * vr,				   sos_uaddr_t uaddr,				   sos_bool_t write_access){  struct elf32_mapped_program * elf32prog_resource;  sos_ret_t     retval = SOS_OK;  sos_paddr_t   ppage_paddr;  sos_uaddr_t   upage_uaddr = SOS_PAGE_ALIGN_INF(uaddr);  sos_uoffset_t offset_in_prog;  sos_size_t    size_to_copy;  sos_ui32_t    access_rights = sos_umem_vmm_get_prot_of_vr(vr);  elf32prog_resource    = (struct elf32_mapped_program*)      sos_umem_vmm_get_mapped_resource_of_vr(vr)->custom_data;  /* Compute the offset in program of the page, and the size to copy     in user space */  offset_in_prog = upage_uaddr - sos_umem_vmm_get_start_of_vr(vr)    + sos_umem_vmm_get_offset_in_resource(vr);  size_to_copy = SOS_PAGE_SIZE;  if (offset_in_prog + size_to_copy > elf32prog_resource->size)    size_to_copy = elf32prog_resource->size - offset_in_prog;  /* If the source page is also aligned, simply remap the kernel area     into user space */  if (SOS_IS_PAGE_ALIGNED(elf32prog_resource->vaddr + offset_in_prog))    {      sos_vaddr_t kern_vaddr = elf32prog_resource->vaddr + offset_in_prog;      ppage_paddr = sos_paging_get_paddr(kern_vaddr);      /* Remap it in user space, in read-only mode (to force COW) */      retval = sos_paging_map(ppage_paddr,			      upage_uaddr,			      TRUE,			      access_rights & ~SOS_VM_MAP_PROT_WRITE);      SOS_ASSERT_FATAL(SOS_OK == retval);    }  /* Otherwise we need to allocate a new page */  else    {      /* Allocate a new page that contains the code/data of the	 program */      ppage_paddr = sos_physmem_ref_physpage_new(FALSE);      if (! ppage_paddr)	return -SOS_ENOMEM;            /* Map it in user space, in read/write mode for the kernel to copy	 the data in the page */      retval = sos_paging_map(ppage_paddr,			      upage_uaddr,			      TRUE,			      access_rights | SOS_VM_MAP_PROT_WRITE);      SOS_ASSERT_FATAL(SOS_OK == retval);      sos_physmem_unref_physpage(ppage_paddr);            /* Copy the program in it */      memcpy((void*)upage_uaddr,	     (void*)elf32prog_resource->vaddr + offset_in_prog,	     size_to_copy);      if (size_to_copy < SOS_PAGE_SIZE)	memset((void*)(upage_uaddr + size_to_copy), 0x0,	       SOS_PAGE_SIZE - size_to_copy);            /* Change it read-only if needed */      if (! (access_rights & SOS_VM_MAP_PROT_WRITE))	return sos_paging_set_prot(upage_uaddr,				   access_rights & ~SOS_VM_MAP_PROT_WRITE);    }     return retval;}static struct sos_umem_vmm_vr_ops elf32prog_ops = (struct sos_umem_vmm_vr_ops){  .ref     = elf32prog_ref,  .unref   = elf32prog_unref,  .page_in = elf32prog_page_in,  .unmap   = NULL /* ignored */};static sos_ret_t elf32prog_mmap(struct sos_umem_vmm_vr *vr){  return sos_umem_vmm_set_ops_of_vr(vr, &elf32prog_ops);}/* * Local functions *//** * Function to locate the given user program image in the kernel memory */static struct userprog_entry * lookup_userprog(const char *name);sos_uaddr_t sos_binfmt_elf32_map(struct sos_umem_vmm_as * dest_as,				 const char * progname){  int i;  /**   * Typedefs, constants and structure definitions as given by the ELF   * standard specifications.   */  typedef unsigned long  Elf32_Addr;  typedef unsigned long  Elf32_Word;  typedef unsigned short Elf32_Half;  typedef unsigned long  Elf32_Off;  typedef signed long    Elf32_Sword;    /* Elf identification */  #define EI_NIDENT 16  typedef struct {    unsigned char       e_ident[EI_NIDENT];    Elf32_Half          e_type;    Elf32_Half          e_machine;    Elf32_Word          e_version;    Elf32_Addr          e_entry;    Elf32_Off           e_phoff;    Elf32_Off           e_shoff;    Elf32_Word          e_flags;    Elf32_Half          e_ehsize;    Elf32_Half          e_phentsize;    Elf32_Half          e_phnum;    Elf32_Half          e_shentsize;    Elf32_Half          e_shnum;    Elf32_Half          e_shstrndx;  } __attribute__((packed)) Elf32_Ehdr_t;  /* e_ident value */#define ELFMAG0 0x7f#define ELFMAG1 'E'#define ELFMAG2 'L'#define ELFMAG3 'F'/* e_ident offsets */#define EI_MAG0         0#define EI_MAG1         1#define EI_MAG2         2#define EI_MAG3         3#define EI_CLASS        4#define EI_DATA         5#define EI_VERSION      6#define EI_PAD          7/* e_ident[EI_CLASS] */#define ELFCLASSNONE    0#define ELFCLASS32      1#define ELFCLASS64      2/* e_ident[EI_DATA] */#define ELFDATANONE     0#define ELFDATA2LSB     1#define ELFDATA2MSB     2/* e_type */#define ET_NONE         0  /* No file type       */#define ET_REL          1  /* Relocatable file   */#define ET_EXEC         2  /* Executable file    */#define ET_DYN          3  /* Shared object file */#define ET_CORE         4  /* Core file          */#define ET_LOPROC  0xff00  /* Processor-specific */#define ET_HIPROC  0xffff  /* Processor-specific *//* e_machine */#define EM_NONE       0  /* No machine     */#define EM_M32        1  /* AT&T WE 32100  */#define EM_SPARC      2  /* SPARC          */#define EM_386        3  /* Intel 80386    */#define EM_68K        4  /* Motorola 68000 */#define EM_88K        5  /* Motorola 88000 */#define EM_860        7  /* Intel 80860    */#define EM_MIPS       8  /* MIPS RS3000    *//* e_version */#define EV_NONE    0 /* invalid version */#define EV_CURRENT 1 /* current version */  typedef struct {    Elf32_Word    p_type;    Elf32_Off     p_offset;    Elf32_Addr    p_vaddr;    Elf32_Addr    p_paddr;    Elf32_Word    p_filesz;    Elf32_Word    p_memsz;    Elf32_Word    p_flags;    Elf32_Word    p_align;  } __attribute__((packed)) Elf32_Phdr_t;/* Reserved segment types p_type */#define PT_NULL    0#define PT_LOAD    1#define PT_DYNAMIC 2#define PT_INTERP  3#define PT_NOTE    4#define PT_SHLIB   5#define PT_PHDR    6#define PT_LOPROC  0x70000000#define PT_HIPROC  0x7fffffff/* p_flags */#define PF_X       1#define PF_W       2#define PF_R       4  Elf32_Ehdr_t *elf_hdr;  Elf32_Phdr_t *elf_phdrs;  struct elf32_mapped_program * mapped_prog;  struct userprog_entry * prog;  sos_uaddr_t prog_top_user_address = 0;  mapped_prog    = (struct elf32_mapped_program*)      sos_kmalloc(sizeof(struct elf32_mapped_program), 0);  if (! mapped_prog)    return -SOS_ENOMEM;  prog = lookup_userprog(progname);  if (! prog)    {      sos_kfree((sos_vaddr_t)mapped_prog);      return 0;    }  /* Initialize mapped resource */  memset(mapped_prog, 0x0, sizeof(*mapped_prog));  mapped_prog->mr.custom_data = mapped_prog;  mapped_prog->mr.mmap        = elf32prog_mmap;  mapped_prog->mr.allowed_access_rights    = SOS_VM_MAP_PROT_READ    | SOS_VM_MAP_PROT_WRITE    | SOS_VM_MAP_PROT_EXEC;  mapped_prog->vaddr          = prog->bottom_vaddr;  mapped_prog->size           = prog->top_vaddr - prog->bottom_vaddr;    elf_hdr = (Elf32_Ehdr_t*) prog->bottom_vaddr;  /* Make sure the image is large enough to contain at least the ELF     header */  if (prog->bottom_vaddr + sizeof(Elf32_Ehdr_t) > prog->top_vaddr)    {      sos_bochs_printf("ELF prog %s: incorrect header\n", prog->name);      return 0;    }  /* Macro to check expected values for some fields in the ELF header */#define ELF_CHECK(hdr,field,expected_value) \  ({ if ((hdr)->field != (expected_value)) \     { \       sos_bochs_printf("ELF prog %s: for %s, expected %x, got %x\n", \			prog->name, \			#field, \			(unsigned)(expected_value), \			(unsigned)(hdr)->field); \       return 0; \     } \  })  ELF_CHECK(elf_hdr, e_ident[EI_MAG0], ELFMAG0);  ELF_CHECK(elf_hdr, e_ident[EI_MAG1], ELFMAG1);  ELF_CHECK(elf_hdr, e_ident[EI_MAG2], ELFMAG2);  ELF_CHECK(elf_hdr, e_ident[EI_MAG3], ELFMAG3);  ELF_CHECK(elf_hdr, e_ident[EI_CLASS], ELFCLASS32);  ELF_CHECK(elf_hdr, e_ident[EI_DATA], ELFDATA2LSB);  ELF_CHECK(elf_hdr, e_type, ET_EXEC);  ELF_CHECK(elf_hdr, e_version, EV_CURRENT);  /* Get the begining of the program header table */  elf_phdrs = (Elf32_Phdr_t*) (prog->bottom_vaddr + elf_hdr->e_phoff);  /* Map the program segment in R/W mode. To make things clean, we     should iterate over the sections, not the program header */  for (i = 0 ; i < elf_hdr->e_phnum ; i++)    {      sos_ui32_t prot_flags;      sos_uaddr_t uaddr;      /* Ignore the empty program headers that are not marked "LOAD" */      if (elf_phdrs[i].p_type != PT_LOAD)	{	  if (elf_phdrs[i].p_memsz != 0)	    {	      sos_display_fatal_error("ELF: non-empty non-LOAD segments not supported yet");	    }	  continue;	}            if (elf_phdrs[i].p_vaddr < SOS_PAGING_BASE_USER_ADDRESS)	{	  sos_display_fatal_error("User program has an incorrect address");	}      prot_flags = 0;      if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_READ)	prot_flags |= SOS_VM_MAP_PROT_READ;      if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_WRITE)	prot_flags |= SOS_VM_MAP_PROT_WRITE;      if (elf_phdrs[i].p_flags & SOS_VM_MAP_PROT_EXEC)	prot_flags |= SOS_VM_MAP_PROT_EXEC;      uaddr = elf_phdrs[i].p_vaddr;      SOS_ASSERT_FATAL(SOS_IS_PAGE_ALIGNED(uaddr));      /* First of all: map the region of the phdr which is also	 covered by the file */      SOS_ASSERT_FATAL(SOS_OK		       == sos_umem_vmm_map(dest_as, &uaddr,					   SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz),					   prot_flags,					   /* PRIVATE */ SOS_VR_MAP_FIXED,					   & mapped_prog->mr,					   elf_phdrs[i].p_offset));      /* Then map the remaining by a zero resource */      uaddr += SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz);      if (SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz)	  < SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz))	SOS_ASSERT_FATAL(SOS_OK			 == sos_dev_zero_map(dest_as, &uaddr,					     SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz)					     - SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_filesz),					     prot_flags,					     /* PRIVATE */ SOS_VR_MAP_FIXED));      if (prog_top_user_address	  < uaddr + SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz))	prog_top_user_address	  = uaddr + SOS_PAGE_ALIGN_SUP(elf_phdrs[i].p_memsz);    }  /* Now prepare the heap */  sos_umem_vmm_init_heap(dest_as, prog_top_user_address);  return elf_hdr->e_entry;}/** * Lookup a user program located inside the kernel's image */static struct userprog_entry * lookup_userprog(const char *name){  struct userprog_entry *prog;  if (! name)    return NULL;  /* Walk through the table of user program description structures to     find the user program with the given name */  for (prog = (struct userprog_entry*) & _userprogs_table ;       prog && (prog->name != NULL) ;       prog++)    {      if (0 == strcmp(name, prog->name))	/* Found it ! */	return prog;    }  return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -