This is the mail archive of the sid@sources.redhat.com mailing list for the SID project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] ELF loader


Hi,

I'm committing the attached patch which requirks the ELF loader to correct the following problems:

1) Flags in the program header table were being used to determine whether an address was part of executable code, however a segment can contain more than one section and they may be a mix of executable and data sections.

2) The table of segments was static and was simply added to for each object file which was loaded. This means that an address was compared against all segments of all executables for a simulation of multiple cpus with multiple programs.

This patch uses the ELF section table to examine each section individually to see if it is executable. The resulting table is also divided into sub tables and each loader gets a pointer to the appropriate sub-table of sections to examine. Each subtable is terminated by an entry of all zeroes.

This patch also removes the hard-coded 100 element limit (which was not checked) on the number of segments and executable sections in favour of dynamic allocation.

Tested against the internal port which exposed the problem and against xstormy16.

Dave
2004-02-12  Dave Brolley  <brolley@redhat.com>

	* elfload.h: Use 'unsigned long long' instead of host_int_8.
	(struct TextSection): Moved here from elfload.c
	(SHF_EXECINSTR): New macro.
	* elfload.c (loadAreas): Now a pointer to a dynamically allocated
	table.
	(textSections): Ditto.
	(newLoadArea): New static function.
	(newTextSection): Ditto.
	(textSectionAddress): Now takes a pointer to a section table.
	(readElfFile): fileHeader, psymHdr, secHdr now automatic arrays.
	Allocate loadAreas and textSections as required. Build textSections
	from the ELF section table; one for each executable loaded.
	* compLoader.cxx (sid::host_int_8): Add 'using' clause.
	(textSegmentAddress): renamed to textSectionAddress and moved to
	elfload.h.
	(setSection_table): New method of loader_probe_bus.
	(SID_GB_WRITE): Call textSectionAddress and pass section_table.
	(section_table): New member of loader_probe_bus.
	(load_it): Get section_table address from readElfFile.
	* Makefile.am (LIBIBERTY): New variable.
	(libloader_la_LIBADD): Add $(LIBIBERTY).
	* Makefile.in: Regenerated.

Index: sid/component/loader/Makefile.am
===================================================================
RCS file: /cvs/src/src/sid/component/loader/Makefile.am,v
retrieving revision 1.2
diff -c -p -r1.2 Makefile.am
*** sid/component/loader/Makefile.am	4 Aug 2001 11:07:50 -0000	1.2
--- sid/component/loader/Makefile.am	12 Feb 2004 20:14:46 -0000
***************
*** 2,7 ****
--- 2,9 ----
  
  AUTOMAKE_OPTIONS = foreign
  
+ LIBIBERTY = -L../../../libiberty -liberty
+ 
  pkglib_LTLIBRARIES = libloader.la
  
  pkgdata_DATA = sw-load-elf.txt
*************** pkgdata_DATA = sw-load-elf.txt
*** 9,14 ****
--- 11,17 ----
  INCLUDES = -I. -I../../include -I$(srcdir)/../../include
  libloader_la_SOURCES = compLoader.cxx elfload.c
  libloader_la_LDFLAGS = -module -no-undefined
+ libloader_la_LIBADD = $(LIBIBERTY)
  
  html_stylesheet=$(srcdir)/../component_html.xsl
  include $(srcdir)/../../config/Makefile.docs
Index: sid/component/loader/compLoader.cxx
===================================================================
RCS file: /cvs/src/src/sid/component/loader/compLoader.cxx,v
retrieving revision 1.6
diff -c -p -r1.6 compLoader.cxx
*** sid/component/loader/compLoader.cxx	21 Oct 2003 21:30:44 -0000	1.6
--- sid/component/loader/compLoader.cxx	12 Feb 2004 20:14:49 -0000
***************
*** 1,6 ****
  // compLoader.cxx - object file loader component.  -*- C++ -*-
  
! // Copyright (C) 1999, 2000, 2003 Red Hat.
  // This file is part of SID and is licensed under the GPL.
  // See the file COPYING.SID for conditions for redistribution.
  
--- 1,6 ----
  // compLoader.cxx - object file loader component.  -*- C++ -*-
  
! // Copyright (C) 1999, 2000, 2003, 2004 Red Hat.
  // This file is part of SID and is licensed under the GPL.
  // See the file COPYING.SID for conditions for redistribution.
  
*************** using sid::bus;
*** 41,46 ****
--- 41,47 ----
  using sid::host_int_1;
  using sid::little_int_1;
  using sid::host_int_4;
+ using sid::host_int_8;
  using sid::component_library;
  using sid::COMPONENT_LIBRARY_MAGIC;
  
*************** using sidutil::std_error_string;
*** 62,69 ****
  
  // A bus for allowing the loader to perform random checks against reads and writes
  // to memory. For example writing to a code area. Default implementation
- extern "C" int textSegmentAddress(int);
- 
  class loader_probe_bus: public sidutil::passthrough_bus
    {
    public:
--- 63,68 ----
*************** class loader_probe_bus: public sidutil::
*** 75,87 ****
      }
      ~loader_probe_bus() throw() {}
      
      // Some macros to make manufacturing of the cartesian-product
      // calls simpler.
  #define SID_GB_WRITE(dtype) \
        sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
  	  { if (LIKELY(*target)) \
                { \
!                 if (write_to_code_address_pin && textSegmentAddress (addr)) \
                    write_to_code_address_pin->drive (addr); \
                  return (*target)->write(addr, data); \
                } \
--- 74,88 ----
      }
      ~loader_probe_bus() throw() {}
      
+     void set_section_table (const struct TextSection *s) { section_table = s; }
+ 
      // Some macros to make manufacturing of the cartesian-product
      // calls simpler.
  #define SID_GB_WRITE(dtype) \
        sid::bus::status write(sid::host_int_4 addr, dtype data) throw ()\
  	  { if (LIKELY(*target)) \
                { \
!                 if (write_to_code_address_pin && textSectionAddress (addr, section_table)) \
                    write_to_code_address_pin->drive (addr); \
                  return (*target)->write(addr, data); \
                } \
*************** class loader_probe_bus: public sidutil::
*** 100,105 ****
--- 101,107 ----
  #undef SID_GB_WRITE
  
      output_pin *write_to_code_address_pin;
+     const struct TextSection *section_table;
    };
  
  class generic_loader: public virtual component,
*************** class elf_loader: public generic_loader
*** 246,253 ****
        elf_loader::freeloader = this;
        unsigned entry_point;
        int little_endian_p;
        int success_p = readElfFile(& elf_loader::load_function,
! 				  & entry_point, & little_endian_p);
        elf_loader::freeloader = 0;
  
        if (success_p)
--- 248,258 ----
        elf_loader::freeloader = this;
        unsigned entry_point;
        int little_endian_p;
+       const struct TextSection *section_table;
        int success_p = readElfFile(& elf_loader::load_function,
! 				  & entry_point, & little_endian_p,
! 				  & section_table);
!       probe_upstream.set_section_table (section_table);
        elf_loader::freeloader = 0;
  
        if (success_p)
Index: sid/component/loader/elfload.c
===================================================================
RCS file: /cvs/src/src/sid/component/loader/elfload.c,v
retrieving revision 1.5
diff -c -p -r1.5 elfload.c
*** sid/component/loader/elfload.c	21 Oct 2003 21:30:44 -0000	1.5
--- sid/component/loader/elfload.c	12 Feb 2004 20:14:49 -0000
***************
*** 1,6 ****
  /* Simple ELF loader
   *
!  * Copyright (c) 1998, 2002 Red Hat
   *
   * The authors hereby grant permission to use, copy, modify, distribute,
   * and license this software and its documentation for any purpose, provided
--- 1,6 ----
  /* Simple ELF loader
   *
!  * Copyright (c) 1998, 2002, 2004 Red Hat
   *
   * The authors hereby grant permission to use, copy, modify, distribute,
   * and license this software and its documentation for any purpose, provided
***************
*** 14,51 ****
   */
  #include <elfload.h>
  #include <unistd.h>
! 
! unsigned char fileHeader [64];
! unsigned char psymHdr[56];
  
  #define PT_LOAD 1
  
! struct LoadAreas
  {
!   host_int_8 loadAddr;
!   host_int_8 filesize;
!   host_int_8 offset;
    int flags;
    int loaded;
! } loadAreas[100]; // XXX: limit on number of loadable sections
  
! static struct TextSegment
  {
!   host_int_8 lbound;
!   host_int_8 hbound;
! } textSegments[100];
! static int textSegmentsCount = 0;
! enum {execute_flag = 1};
  
  
  int
! textSegmentAddress (int address)
  {
    int i;
!   for (i = 0; i < textSegmentsCount ; i++)
      {
!       if (textSegments[i].lbound <= address
! 	  && address <= textSegments[i].hbound)
  	return 1;
      }
    return 0;
--- 14,70 ----
   */
  #include <elfload.h>
  #include <unistd.h>
! #include "libiberty.h"
  
  #define PT_LOAD 1
  
! /* The loadAreas table is reused by each loader.  */
! static struct LoadAreas
  {
!   unsigned long long loadAddr;
!   unsigned long long filesize;
!   unsigned long long offset;
    int flags;
    int loaded;
! } *loadAreas = 0;
  
! static void
! newLoadArea (int index)
  {
!   static loadAreaNum = 0;
!   if (index >= loadAreaNum)
!     {
!       loadAreaNum = index + 10;
!       loadAreas = xrealloc (loadAreas, loadAreaNum * sizeof (*loadAreas));
!     }
! }
! 
! /* The section table is kept for the duration of the simulation.
!    It is divided into sub tables, one for each loader in the system.  */
! static int textSectionCount = 0;
! static struct TextSection *textSections = 0;
  
+ static void
+ newTextSection (int index)
+ {
+   static textSectionNum = 0;
+   if (index >= textSectionNum)
+     {
+       textSectionNum = index + 10;
+       textSections = xrealloc (textSections, textSectionNum * sizeof (*textSections));
+     }
+ }
  
  int
! textSectionAddress (unsigned long long address, const struct TextSection *section_table)
  {
+   /* The table begins with the given pointer and is terminated by an entry with
+      zeroes for both the high and low bounds.  */
    int i;
!   for (i = 0; section_table[i].lbound != 0 || section_table[i].hbound != 0; i++)
      {
!       if (section_table[i].lbound <= address
! 	  && address <= section_table[i].hbound)
  	return 1;
      }
    return 0;
*************** textSegmentAddress (int address)
*** 59,74 ****
  */
  
  int
! readElfFile (PFLOAD func, unsigned* entry_point, int* little_endian)
  {
!   host_int_8 psymOffset;
    int psymSize;
    int psymNum;
!   host_int_8 entryPoint = 0;
!   int loadAreaCount = 0;
    int x;
    int littleEndian;
    int sixtyfourbit;
  
    /* This is relatively straightforward. We first read in the file header,
       find out how many sections there are, determine which ones are loadable
--- 78,99 ----
  */
  
  int
! readElfFile (PFLOAD func, unsigned* entry_point, int* little_endian, const struct TextSection **section_table)
  {
!   unsigned char fileHeader [64];
!   unsigned char psymHdr [56];
!   unsigned char secHdr [64];
!   unsigned long long psymOffset;
    int psymSize;
    int psymNum;
!   unsigned long long secOffset;
!   int secSize;
!   int secNum;
!   unsigned long long entryPoint = 0;
    int x;
    int littleEndian;
    int sixtyfourbit;
+   int loadAreaCount = 0;
  
    /* This is relatively straightforward. We first read in the file header,
       find out how many sections there are, determine which ones are loadable
*************** readElfFile (PFLOAD func, unsigned* entr
*** 77,83 ****
       There is one major failing, tho--if the psym header isn't at the front
       of the file, and we're loading from a stream that we can't back
       up on, we will lose.  */
!   if (func (NULL, fileHeader, 0, 64, 0) != 64)
      {
        return 0;
      }
--- 102,108 ----
       There is one major failing, tho--if the psym header isn't at the front
       of the file, and we're loading from a stream that we can't back
       up on, we will lose.  */
!   if (func (0, fileHeader, 0, 64, 0) != 64)
      {
        return 0;
      }
*************** readElfFile (PFLOAD func, unsigned* entr
*** 108,121 ****
      }
    for (x = 0; x < psymNum; x++)
      {
        if (sixtyfourbit)
          {
- 	  if (func (NULL, psymHdr, psymOffset, 56, 0) != 56)
- 	    {
- 	      return 0;
- 	    }
  	  if (fetchWord (psymHdr, littleEndian) == PT_LOAD)
  	    {
  	      loadAreas[loadAreaCount].loadAddr = fetchQuad(psymHdr+24,
  							    littleEndian);
  	      loadAreas[loadAreaCount].offset = fetchQuad(psymHdr+8, littleEndian);
--- 133,147 ----
      }
    for (x = 0; x < psymNum; x++)
      {
+       if (func (0, psymHdr, psymOffset, psymSize, 0) != psymSize)
+ 	{
+ 	  return 0;
+ 	}
        if (sixtyfourbit)
          {
  	  if (fetchWord (psymHdr, littleEndian) == PT_LOAD)
  	    {
+ 	      newLoadArea (loadAreaCount);
  	      loadAreas[loadAreaCount].loadAddr = fetchQuad(psymHdr+24,
  							    littleEndian);
  	      loadAreas[loadAreaCount].offset = fetchQuad(psymHdr+8, littleEndian);
*************** readElfFile (PFLOAD func, unsigned* entr
*** 123,150 ****
  							    littleEndian);
  	      loadAreas[loadAreaCount].flags = fetchWord(psymHdr+4, littleEndian);
  	      loadAreas[loadAreaCount].loaded = 0;
- 	      
- 	      if (loadAreas[loadAreaCount].flags & execute_flag)
- 		{
- 		  textSegments[textSegmentsCount].lbound = 
- 		    loadAreas[loadAreaCount].loadAddr;
- 		  textSegments[textSegmentsCount].hbound = 
- 		    loadAreas[loadAreaCount].loadAddr
- 		    + loadAreas[loadAreaCount].filesize;
- 		  textSegmentsCount++;
- 		}
- 
  	      loadAreaCount++;
  	    }
          }
        else
          {
- 	  if (func (NULL, psymHdr, psymOffset, 32, 0) != 32)
- 	    {
- 	      return 0;
- 	    }
  	  if (fetchWord (psymHdr, littleEndian) == PT_LOAD)
  	    {
  	      loadAreas[loadAreaCount].loadAddr = fetchWord(psymHdr+12,
  								    littleEndian);
  	      loadAreas[loadAreaCount].offset = fetchWord(psymHdr+4, littleEndian);
--- 149,162 ----
  							    littleEndian);
  	      loadAreas[loadAreaCount].flags = fetchWord(psymHdr+4, littleEndian);
  	      loadAreas[loadAreaCount].loaded = 0;
  	      loadAreaCount++;
  	    }
          }
        else
          {
  	  if (fetchWord (psymHdr, littleEndian) == PT_LOAD)
  	    {
+ 	      newLoadArea (loadAreaCount);
  	      loadAreas[loadAreaCount].loadAddr = fetchWord(psymHdr+12,
  								    littleEndian);
  	      loadAreas[loadAreaCount].offset = fetchWord(psymHdr+4, littleEndian);
*************** readElfFile (PFLOAD func, unsigned* entr
*** 152,168 ****
  							    littleEndian);
  	      loadAreas[loadAreaCount].flags = fetchWord(psymHdr+24, littleEndian);
  	      loadAreas[loadAreaCount].loaded = 0;
- 
- 	      if (loadAreas[loadAreaCount].flags & execute_flag)
- 		{
- 		  textSegments[textSegmentsCount].lbound = 
- 		    loadAreas[loadAreaCount].loadAddr;
- 		  textSegments[textSegmentsCount].hbound = 
- 		    loadAreas[loadAreaCount].loadAddr
- 		    + loadAreas[loadAreaCount].filesize;
- 		  textSegmentsCount++;
- 		}
- 
  	      loadAreaCount++;
  	    }
          }
--- 164,169 ----
*************** readElfFile (PFLOAD func, unsigned* entr
*** 200,205 ****
--- 201,262 ----
  
    /* FIXME: If no program segment header, loop over sections instead.  */
    /* FIXME: admin part of program segment is loaded.  */
+ 
+   /* Look in the section table in order to determine which sections contain
+      code and which contain data.  */
+   newTextSection (textSectionCount);
+   *section_table = textSections + textSectionCount;
+   if (sixtyfourbit) 
+     {
+       secOffset = fetchQuad (fileHeader+40, littleEndian);
+       secSize = fetchShort (fileHeader+58, littleEndian);
+       secNum = fetchShort (fileHeader+60, littleEndian);
+     }
+   else
+     {
+       secOffset = fetchWord (fileHeader+32, littleEndian);
+       secSize = fetchShort (fileHeader+46, littleEndian);
+       secNum = fetchShort (fileHeader+48, littleEndian);
+     }
+   for (x = 0; x < secNum; x++)
+     {
+       if (func (0, secHdr, secOffset, secSize, 0) != secSize)
+ 	{
+ 	  return 0;
+ 	}
+       if (sixtyfourbit)
+         {
+ 	  if (fetchQuad(secHdr+8, littleEndian) & SHF_EXECINSTR)
+ 	    {
+ 	      textSections[textSectionCount].lbound = 
+ 		fetchQuad(secHdr+24, littleEndian);
+ 	      textSections[textSectionCount].hbound = 
+ 		textSections[textSectionCount].lbound
+ 		+ fetchQuad(secHdr+32, littleEndian) - 1;
+ 	      textSectionCount++;
+ 	      newTextSection (textSectionCount);
+ 	    }
+         }
+       else
+         {
+ 	  if (fetchWord(secHdr+8, littleEndian) & SHF_EXECINSTR)
+ 	    {
+ 	      textSections[textSectionCount].lbound = 
+ 		fetchWord(secHdr+16, littleEndian);
+ 	      textSections[textSectionCount].hbound = 
+ 		textSections[textSectionCount].lbound
+ 		+ fetchWord(secHdr+20, littleEndian) - 1;
+ 	      textSectionCount++;
+ 	      newTextSection (textSectionCount);
+ 	    }
+         }
+       secOffset += secSize;
+     }
+ 
+   /* Terminate this portion of the section table.  */
+   textSections[textSectionCount].lbound = 0;
+   textSections[textSectionCount].hbound = 0;
+   textSectionCount++;
  
    *entry_point = entryPoint;
    *little_endian = littleEndian;
Index: sid/component/loader/elfload.h
===================================================================
RCS file: /cvs/src/src/sid/component/loader/elfload.h,v
retrieving revision 1.3
diff -c -p -r1.3 elfload.h
*** sid/component/loader/elfload.h	21 Oct 2003 21:30:44 -0000	1.3
--- sid/component/loader/elfload.h	12 Feb 2004 20:14:49 -0000
***************
*** 1,6 ****
  /* Header for simple ELF loader
   *
!  * Copyright (c) 1998 Red Hat
   *
   * The authors hereby grant permission to use, copy, modify, distribute,
   * and license this software and its documentation for any purpose, provided
--- 1,6 ----
  /* Header for simple ELF loader
   *
!  * Copyright (c) 1998, 2004 Red Hat
   *
   * The authors hereby grant permission to use, copy, modify, distribute,
   * and license this software and its documentation for any purpose, provided
***************
*** 18,31 ****
  #define BYTE(X,offset) (((X)[offset]) & 255)
  #define fetchShortLittle(addr) (BYTE((addr),1)*256+BYTE((addr),0))
  #define fetchWordLittle(addr) (fetchShortLittle (addr) + fetchShortLittle((addr) + 2) * 65536)
! #define fetchQuadLittle(addr) (fetchWordLittle ((addr)) + ((host_int_8)fetchWordLittle((addr) + 4) << 32))
  #define fetchShortBig(addr) (BYTE((addr),0)*256+BYTE((addr),1))
  #define fetchWordBig(addr) (fetchShortBig (addr) * 65536 + fetchShortBig((addr) + 2))
! #define fetchQuadBig(addr) (((host_int_8)fetchWordBig ((addr)) << 32) + fetchWordBig((addr) + 4))
  #define fetchShort(ADDR,LITTLE) ((LITTLE) ? fetchShortLittle((ADDR)) : fetchShortBig((ADDR)))
  #define fetchWord(ADDR,LITTLE) ((LITTLE) ? fetchWordLittle((ADDR)) : fetchWordBig((ADDR)))
  #define fetchQuad(ADDR,LITTLE) ((LITTLE) ? fetchQuadLittle((ADDR)) : fetchQuadBig((ADDR)))
  
  /* 
     PFLOAD represents a function that will read file data. 
     DEST or DEST2 is used as the destination address to be written with the
--- 18,37 ----
  #define BYTE(X,offset) (((X)[offset]) & 255)
  #define fetchShortLittle(addr) (BYTE((addr),1)*256+BYTE((addr),0))
  #define fetchWordLittle(addr) (fetchShortLittle (addr) + fetchShortLittle((addr) + 2) * 65536)
! #define fetchQuadLittle(addr) (fetchWordLittle ((addr)) + ((unsigned long long)fetchWordLittle((addr) + 4) << 32))
  #define fetchShortBig(addr) (BYTE((addr),0)*256+BYTE((addr),1))
  #define fetchWordBig(addr) (fetchShortBig (addr) * 65536 + fetchShortBig((addr) + 2))
! #define fetchQuadBig(addr) (((unsigned long long)fetchWordBig ((addr)) << 32) + fetchWordBig((addr) + 4))
  #define fetchShort(ADDR,LITTLE) ((LITTLE) ? fetchShortLittle((ADDR)) : fetchShortBig((ADDR)))
  #define fetchWord(ADDR,LITTLE) ((LITTLE) ? fetchWordLittle((ADDR)) : fetchWordBig((ADDR)))
  #define fetchQuad(ADDR,LITTLE) ((LITTLE) ? fetchQuadLittle((ADDR)) : fetchQuadBig((ADDR)))
  
+ struct TextSection
+ {
+   unsigned long long lbound;
+   unsigned long long hbound;
+ };
+ 
  /* 
     PFLOAD represents a function that will read file data. 
     DEST or DEST2 is used as the destination address to be written with the
***************
*** 37,50 ****
     If OFFSET and AMOUNT are both negative, then the file should be
     closed (any remaining bytes are to be ignored). */
  
! typedef unsigned long long host_int_8;	/* XXX */
! 
! typedef int (*PFLOAD)(host_int_8 dest, char *dest2, host_int_8 offset, host_int_8 amount, int insn_space);
  /* Is address in the text segment? */
! extern int textSegmentAddress(int);
  /* Load an ELF executable into memory. FUNC is used to actually read the
     file. */
! extern int readElfFile(PFLOAD func, unsigned*, int*);
  
  #define EI_CLASS 4
  #define ELFCLASS64  2 /* 64 bit */
--- 43,54 ----
     If OFFSET and AMOUNT are both negative, then the file should be
     closed (any remaining bytes are to be ignored). */
  
! typedef int (*PFLOAD)(unsigned long long dest, char *dest2, unsigned long long offset, unsigned long long amount, int insn_space);
  /* Is address in the text segment? */
! extern int textSectionAddress(unsigned long long, const struct TextSection *);
  /* Load an ELF executable into memory. FUNC is used to actually read the
     file. */
! extern int readElfFile(PFLOAD func, unsigned*, int*, const struct TextSection **);
  
  #define EI_CLASS 4
  #define ELFCLASS64  2 /* 64 bit */
*************** extern int readElfFile(PFLOAD func, unsi
*** 55,59 ****
--- 59,66 ----
  /* Elf program header flags */
  #define PF_X	0x01	/* executable */
  #define PF_R	0x04	/* readable */
+ 
+ /* ELF section header flags */
+ #define SHF_EXECINSTR	(1 << 2)	/* Executable machine instructions */
  
  #endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]