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


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

Improvements to section to segment mapping


Hi Guys,

  I am considering checking in the patch below, but I wanted to give
  people a chance to look it over first in case they have any comments.

  The patch tidies up the piece of code in elf.c that handles the
  mapping of sections to segments.  This came about because a customer
  had noticed that if they used objcopy to change the LMAs of some
  sections (but not all of them), the resulting segment map was
  broken.

  The patch does several things.  It adds a new boolean flag to the
  asection structure, which is used to mark when a section has been
  allocated to a segment.

  It creates a couple of new macros to replace duplicated code, and it
  streamlines the code that uses them.  It also adds code to cope with
  the case where overlapping segments have been created (again by
  objcopy) - it fixes the segments to remove the overlaps.

  It also allows new segments to be created, even beyond the number
  originally estimated in ihdr->e_phnum.  It adjusts the appropriate
  fields if it had to generate extra segments.

  I have tested this code with an x86 Linux native build and an
  arm-elf cross compiler and everything worked OK.  I am running a
  Solaris build and a Linux bootstrap at the moment, just in case
  there are any unforeseen problems. 

  So unless there are any objections I will probably check this patch
  in next week.

Cheers
	Nick


2000-07-28  Nick Clifton  <nickc@cygnus.com>

	* section.c (struct sec): Add new boolean field 'segment_mark'.
	(STD_SECTION): Initialise new field to zero.

	* bfd-in2.h: Regenerate.

	* elf.c (copy_private_bfd_data): Reorganise section to segment 
	mapping to cope with moved sections requiring new segments,
	and overlapping segments.
	(SEGMENT_END): New macro: Return the end address of a segment.
	(IS_CONTAINED_BY_VMA): New macro: Determine if a segment
	contains a section by comparing their VMA addresses.
	(IS_CONTAINED_BY_LMA): New macro: Determine if a segment
	contains a section by comparing their LMA addresses.
	(INCLUDE_SECTION_IN_SEGMENT): New macro: Determine if a
	section should be included in a segment.
	(SEGMENT_AFTER_SEGMENT): New macro: Determine if one segment
	follows another in memory.
	(SEGMENT_OVERLAPS_SEGMENT): New macro: Determine if two
	segments overlap.

Index: section.c
===================================================================
RCS file: /cvs/src//src/bfd/section.c,v
retrieving revision 1.16
diff -p -r1.16 section.c
*** section.c	2000/07/10 02:05:40	1.16
--- section.c	2000/07/28 18:56:49
*************** CODE_FRAGMENT
*** 363,368 ****
--- 363,371 ----
  .  {* A mark flag used by some linker backends for garbage collection.  *}
  .  unsigned int gc_mark : 1;
  .
+ .  {* Used by the ELF code to mark sections which have been allocated to segments.  *}
+ .  unsigned int segment_mark : 1;
+ .
  .  {* End of internal packed boolean fields.  *}
  .
  .  {*  The virtual memory address of the section - where it will be
*************** static const asymbol global_syms[] =
*** 549,565 ****
    GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, &bfd_ind_section)
  };
  
! #define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX)	\
!   const asymbol * const SYM = (asymbol *) &global_syms[IDX]; \
!   const asection SEC = \
      /* name, id,  index, next, flags, user_set_vma, reloc_done,      */	\
      { NAME,  IDX, 0,     NULL, FLAGS, 0,            0,			\
  									\
!     /* linker_mark, gc_mark, vma, lma, _cooked_size, _raw_size,      */	\
!        0,           0,       0,   0,   0,            0,			\
  									\
!     /* output_offset, output_section,      alignment_power,          */	\
!        0,             (struct sec *) &SEC, 0,				\
  									\
      /* relocation, orelocation, reloc_count, filepos, rel_filepos,   */	\
         NULL,       NULL,        0,           0,       0,		\
--- 552,568 ----
    GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, &bfd_ind_section)
  };
  
! #define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX)				\
!   const asymbol * const SYM = (asymbol *) &global_syms[IDX]; 		\
!   const asection SEC = 							\
      /* name, id,  index, next, flags, user_set_vma, reloc_done,      */	\
      { NAME,  IDX, 0,     NULL, FLAGS, 0,            0,			\
  									\
!     /* linker_mark, gc_mark, segment_mark, vma, lma, _cooked_size,   */	\
!        0,           0,       0,            0,   0,   0,            	\
  									\
!     /* _raw_size, output_offset, output_section,    alignment_power, */ \
!        0,         0,           (struct sec *) &SEC, 0,			\
  									\
      /* relocation, orelocation, reloc_count, filepos, rel_filepos,   */	\
         NULL,       NULL,        0,           0,       0,		\

Index: elf.c
===================================================================
RCS file: /cvs/src//src/bfd/elf.c,v
retrieving revision 1.44
diff -p -r1.44 elf.c
*** elf.c	2000/07/20 16:21:06	1.44
--- elf.c	2000/07/28 18:56:50
*************** copy_private_bfd_data (ibfd, obfd)
*** 3619,3624 ****
--- 3619,3628 ----
    unsigned int i;
    unsigned int num_segments;
    boolean phdr_included = false;
+   asection *s;
+   bfd_vma maxpagesize;
+   struct elf_segment_map * phdr_adjust_seg = NULL;
+   unsigned int phdr_adjust_num = 0;
  
    if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
        || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
*************** copy_private_bfd_data (ibfd, obfd)
*** 3633,3673 ****
    pm = &mfirst;
  
    num_segments = elf_elfheader (ibfd)->e_phnum;
  
! #define IS_CONTAINED_BY(addr, len, bottom, phdr)		 	\
! 	  ((addr) >= (bottom)				 	  	\
! 	   && (   ((addr) + (len)) <= ((bottom) + (phdr)->p_memsz)	\
! 	       || ((addr) + (len)) <= ((bottom) + (phdr)->p_filesz)))
  
    /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
! 
! #define IS_COREFILE_NOTE(p, s)                                          \
! 	    (p->p_type == PT_NOTE                                       \
! 	     && bfd_get_format (ibfd) == bfd_core                       \
! 	     && s->vma == 0 && s->lma == 0                              \
! 	     && (bfd_vma) s->filepos >= p->p_offset                     \
! 	     && (bfd_vma) s->filepos + s->_raw_size                     \
  	     <= p->p_offset + p->p_filesz)
  
    /* The complicated case when p_vaddr is 0 is to handle the Solaris
       linker, which generates a PT_INTERP section with p_vaddr and
       p_memsz set to 0.  */
! 
! #define IS_SOLARIS_PT_INTERP(p, s)					\
! 	    (p->p_vaddr == 0						\
! 	     && p->p_filesz > 0						\
! 	     && (s->flags & SEC_HAS_CONTENTS) != 0			\
! 	     && s->_raw_size > 0					\
! 	     && (bfd_vma) s->filepos >= p->p_offset			\
! 	     && ((bfd_vma) s->filepos + s->_raw_size			\
  		     <= p->p_offset + p->p_filesz))
  
    /* Scan through the segments specified in the program header
!      of the input BFD.  */
    for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i++, p++)
      {
        unsigned int csecs;
-       asection *s;
        asection **sections;
        asection *os;
        unsigned int isec;
--- 3637,3773 ----
    pm = &mfirst;
  
    num_segments = elf_elfheader (ibfd)->e_phnum;
+   maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
  
!   /* Returns the end address of the segment + 1.  */
! #define SEGMENT_END(segment, start) 			\
!   (start + (segment->p_memsz > segment->p_filesz 	\
!    ? segment->p_memsz : segment->p_filesz))
! 
!   /* Returns true if the given section is contained within
!      the given segment.  VMA addresses are compared.  */
! #define IS_CONTAINED_BY_VMA(section, segment)		\
!   (section->vma >= segment->p_vaddr			\
!    && (section->vma + section->_raw_size)		\
!    <= (SEGMENT_END (segment, segment->p_vaddr)))
!     
!   /* Returns true if the given section is contained within
!      the given segment.  LMA addresses are compared.  */
! #define IS_CONTAINED_BY_LMA(section, segment, base)	\
!     (section->lma >= base				\
!      && (section->lma + section->_raw_size)		\
!      <= SEGMENT_END (segment, base))
  
    /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
! #define IS_COREFILE_NOTE(p, s)                          \
! 	    (p->p_type == PT_NOTE                       \
! 	     && bfd_get_format (ibfd) == bfd_core       \
! 	     && s->vma == 0 && s->lma == 0              \
! 	     && (bfd_vma) s->filepos >= p->p_offset     \
! 	     && (bfd_vma) s->filepos + s->_raw_size     \
  	     <= p->p_offset + p->p_filesz)
  
    /* The complicated case when p_vaddr is 0 is to handle the Solaris
       linker, which generates a PT_INTERP section with p_vaddr and
       p_memsz set to 0.  */
! #define IS_SOLARIS_PT_INTERP(p, s)			\
! 	    (p->p_vaddr == 0				\
! 	     && p->p_filesz > 0				\
! 	     && (s->flags & SEC_HAS_CONTENTS) != 0	\
! 	     && s->_raw_size > 0			\
! 	     && (bfd_vma) s->filepos >= p->p_offset	\
! 	     && ((bfd_vma) s->filepos + s->_raw_size	\
  		     <= p->p_offset + p->p_filesz))
  
+   /* Decide if the given section should be included in the given segment.
+      A section will be included if:
+        1. It is within the address space of the segment,
+        2. It is an allocated segment,
+        3. There is an output section associated with it,
+        4. The section has not already been allocated to a previous segment.  */
+ #define INCLUDE_SECTION_IN_SEGMENT(section, segment)	\
+   ((((IS_CONTAINED_BY_VMA (section, segment) 		\
+       || IS_SOLARIS_PT_INTERP (segment, section))	\
+      && (section->flags & SEC_ALLOC) != 0)		\
+     || IS_COREFILE_NOTE (segment, section))		\
+    && section->output_section != NULL			\
+    && section->segment_mark == false)
+ 
+   /* Returns true iff seg1 starts after the end of seg2.  */
+ #define SEGMENT_AFTER_SEGMENT(seg1, seg2)		\
+     (seg1->p_vaddr >= SEGMENT_END (seg2, seg2->p_vaddr))
+ 
+   /* Returns true iff seg1 and seg2 overlap.  */
+ #define SEGMENT_OVERLAPS(seg1, seg2)			\
+   (!(SEGMENT_AFTER_SEGMENT (seg1, seg2) && SEGMENT_AFTER_SEGMENT (seg2, seg1)))
+ 
+   
+   /* Initialise the segment mark field.  */
+   for (s = ibfd->sections; s != NULL; s = s->next)
+     s->segment_mark = false;
+ 
    /* Scan through the segments specified in the program header
!      of the input BFD.  For this first scan we look for overlaps.
!      These can be created by wierd parameters to objcopy.  */
!   for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i ++, p ++)
!     {
!       unsigned int j;
!       Elf_Internal_Phdr * pp;
! 
!       if (p->p_type == PT_NULL)
! 	continue;
!       
!       /* Determine if this segment overlaps any previous segments.
! 	 This can happen when objcopy is used to adjust section LMAs.  */
!       for (j = 0, pp = elf_tdata (ibfd)->phdr; j < i; j ++, pp ++)
! 	{
! 	  bfd_signed_vma extra_length;
! 	  
! 	  
! 	  if (pp->p_type == PT_NULL || ! SEGMENT_OVERLAPS (p, pp))
! 	    continue;
! 	  
! 	  /* Merge the two segments together.  */
! 	  if (pp->p_vaddr < p->p_vaddr)
! 	    {
! 	      /* Extend PP to include P and then delete P.  */
! 	      extra_length =
! 		SEGMENT_END (p, p->p_vaddr) - SEGMENT_END (pp, pp->p_vaddr);
! 	      
! 	      if (extra_length > 0)
! 		{
! 		  pp->p_memsz  += extra_length;
! 		  pp->p_filesz += extra_length;
! 		}
! 	      
! 	      p->p_type = PT_NULL;
! 	      
! 	      /* Since we have deleted P we must restart the outer loop.  */
! 	      i = 0;
! 	      p = elf_tdata (ibfd)->phdr;
! 	      break;
! 	    }
! 	  else
! 	    {
! 	      /* Extend P to include PP and then delete PP.  */
! 	      extra_length =
! 		SEGMENT_END (pp, pp->p_vaddr) - SEGMENT_END (p, p->p_vaddr);
! 	      
! 	      if (extra_length > 0)
! 		{
! 		  p->p_memsz  += extra_length;
! 		  p->p_filesz += extra_length;
! 		}
! 	      
! 	      pp->p_type = PT_NULL;
! 	    }
! 	}
!     }
!   
!   /* The second scan attempts to assign sections to segments.  */
    for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i++, p++)
      {
        unsigned int csecs;
        asection **sections;
        asection *os;
        unsigned int isec;
*************** copy_private_bfd_data (ibfd, obfd)
*** 3675,3696 ****
        bfd_vma suggested_lma;
        unsigned int j;
  
!       /* For each section in the input BFD, decide if it should be
! 	 included in the current segment.  A section will be included
! 	 if it is within the address space of the segment, and it is
! 	 an allocated segment, and there is an output section
! 	 associated with it.  */
        csecs = 0;
        for (s = ibfd->sections; s != NULL; s = s->next)
! 	if (s->output_section != NULL)
! 	  {
! 	    if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
! 		 || IS_SOLARIS_PT_INTERP (p, s))
! 		&& (s->flags & SEC_ALLOC) != 0)
! 	      ++csecs;
! 	    else if (IS_COREFILE_NOTE (p, s))
! 	      ++csecs;
! 	  }
  
        /* Allocate a segment map big enough to contain all of the
  	 sections we have selected.  */
--- 3775,3788 ----
        bfd_vma suggested_lma;
        unsigned int j;
  
!       if (p->p_type == PT_NULL)
! 	continue;
!       
!       /* Compute how many sections might be placed into this segment.  */
        csecs = 0;
        for (s = ibfd->sections; s != NULL; s = s->next)
! 	if (INCLUDE_SECTION_IN_SEGMENT (s, p))
! 	  ++csecs;
  
        /* Allocate a segment map big enough to contain all of the
  	 sections we have selected.  */
*************** copy_private_bfd_data (ibfd, obfd)
*** 3733,3739 ****
  	  /* Special segments, such as the PT_PHDR segment, may contain
  	     no sections, but ordinary, loadable segments should contain
  	     something.  */
- 
  	  if (p->p_type == PT_LOAD)
  	      _bfd_error_handler
  		(_("%s: warning: Empty loadable segment detected\n"),
--- 3825,3830 ----
*************** copy_private_bfd_data (ibfd, obfd)
*** 3784,3804 ****
  	 case, where the sections have not been moved, this means that
  	 we have completely filled the segment, and there is nothing
  	 more to do.  */
- 
        isec = 0;
        matching_lma = 0;
        suggested_lma = 0;
  
        for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
  	{
! 	  os = s->output_section;
! 
! 	  if ((((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
! 		 || IS_SOLARIS_PT_INTERP (p, s))
! 		&& (s->flags & SEC_ALLOC) != 0)
! 	       || IS_COREFILE_NOTE (p, s))
! 	      && os != NULL)
  	    {
  	      sections[j++] = s;
  
  	      /* The Solaris native linker always sets p_paddr to 0.
--- 3875,3890 ----
  	 case, where the sections have not been moved, this means that
  	 we have completely filled the segment, and there is nothing
  	 more to do.  */
        isec = 0;
        matching_lma = 0;
        suggested_lma = 0;
  
        for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
  	{
! 	  if (INCLUDE_SECTION_IN_SEGMENT (s, p))
  	    {
+ 	      os = s->output_section;
+ 
  	      sections[j++] = s;
  
  	      /* The Solaris native linker always sets p_paddr to 0.
*************** copy_private_bfd_data (ibfd, obfd)
*** 3819,3832 ****
  
  	      /* Match up the physical address of the segment with the
  		 LMA address of the output section.  */
! 	      if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
  		  || IS_COREFILE_NOTE (p, s))
  		{
  		  if (matching_lma == 0)
  		    matching_lma = os->lma;
  
  		  /* We assume that if the section fits within the segment
! 		     that it does not overlap any other section within that
  		     segment.  */
  		  m->sections[isec++] = os;
  		}
--- 3905,3918 ----
  
  	      /* Match up the physical address of the segment with the
  		 LMA address of the output section.  */
! 	      if (IS_CONTAINED_BY_LMA (os, p, m->p_paddr)
  		  || IS_COREFILE_NOTE (p, s))
  		{
  		  if (matching_lma == 0)
  		    matching_lma = os->lma;
  
  		  /* We assume that if the section fits within the segment
! 		     then it does not overlap any other section within that
  		     segment.  */
  		  m->sections[isec++] = os;
  		}
*************** copy_private_bfd_data (ibfd, obfd)
*** 3859,3865 ****
  	      /* At least one section fits inside the current segment.
  		 Keep it, but modify its physical address to match the
  		 LMA of the first section that fitted.  */
- 
  	      m->p_paddr = matching_lma;
  	    }
  	  else
--- 3945,3950 ----
*************** copy_private_bfd_data (ibfd, obfd)
*** 3867,3883 ****
  	      /* None of the sections fitted inside the current segment.
  		 Change the current segment's physical address to match
  		 the LMA of the first section.  */
- 
  	      m->p_paddr = suggested_lma;
  	    }
  
! 	  /* Offset the segment physical address from the lma to allow
! 	     for space taken up by elf headers.  */
  	  if (m->includes_filehdr)
  	    m->p_paddr -= iehdr->e_ehsize;
  
  	  if (m->includes_phdrs)
! 	    m->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
  	}
  
        /* Step Three: Loop over the sections again, this time assigning
--- 3952,3977 ----
  	      /* None of the sections fitted inside the current segment.
  		 Change the current segment's physical address to match
  		 the LMA of the first section.  */
  	      m->p_paddr = suggested_lma;
  	    }
  
! 	  /* Offset the segment physical address from the lma
! 	     to allow for space taken up by elf headers.  */
  	  if (m->includes_filehdr)
  	    m->p_paddr -= iehdr->e_ehsize;
  
  	  if (m->includes_phdrs)
! 	    {
! 	      m->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
! 
! 	      /* iehdr->e_phnum is just an estimate of the number
! 		 of program headers that we will need.  Make a note
! 		 here of the number we used and the segment we chose
! 		 to hold these headers, so that we can adjust the
! 		 offset when we know the correct value.  */
! 	      phdr_adjust_num = iehdr->e_phnum;
! 	      phdr_adjust_seg = m;
! 	    }
  	}
  
        /* Step Three: Loop over the sections again, this time assigning
*************** copy_private_bfd_data (ibfd, obfd)
*** 3903,3909 ****
  
  	      os = s->output_section;
  
! 	      if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
  		  || IS_COREFILE_NOTE (p, s))
  		{
  		  if (m->count == 0)
--- 3997,4005 ----
  
  	      os = s->output_section;
  
! 	      BFD_ASSERT (os != NULL);
! 	      
! 	      if (IS_CONTAINED_BY_LMA (os, p, m->p_paddr)
  		  || IS_COREFILE_NOTE (p, s))
  		{
  		  if (m->count == 0)
*************** copy_private_bfd_data (ibfd, obfd)
*** 3921,3936 ****
  		  else
  		    {
  		      asection * prev_sec;
- 		      bfd_vma maxpagesize;
  
  		      prev_sec = m->sections[m->count - 1];
- 		      maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
  
  		      /* If the gap between the end of the previous section
  			 and the start of this section is more than maxpagesize
  			 then we need to start a new segment.  */
! 		      if (BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize)
  			  < BFD_ALIGN (os->lma, maxpagesize))
  			{
  			  if (suggested_lma == 0)
  			    suggested_lma = os->lma;
--- 4017,4031 ----
  		  else
  		    {
  		      asection * prev_sec;
  
  		      prev_sec = m->sections[m->count - 1];
  
  		      /* If the gap between the end of the previous section
  			 and the start of this section is more than maxpagesize
  			 then we need to start a new segment.  */
! 		      if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize)
  			  < BFD_ALIGN (os->lma, maxpagesize))
+ 			  || ((prev_sec->lma + prev_sec->_raw_size) > os->lma))
  			{
  			  if (suggested_lma == 0)
  			    suggested_lma = os->lma;
*************** copy_private_bfd_data (ibfd, obfd)
*** 3942,3947 ****
--- 4037,4043 ----
  		  m->sections[m->count++] = os;
  		  ++isec;
  		  sections[j] = NULL;
+ 		  s->segment_mark = true;
  		}
  	      else if (suggested_lma == 0)
  		suggested_lma = os->lma;
*************** copy_private_bfd_data (ibfd, obfd)
*** 3958,3964 ****
  	      /* We still have not allocated all of the sections to
  		 segments.  Create a new segment here, initialise it
  		 and carry on looping.  */
- 
  	      m = ((struct elf_segment_map *)
  		   bfd_alloc (obfd,
  			      (sizeof (struct elf_segment_map)
--- 4054,4059 ----
*************** copy_private_bfd_data (ibfd, obfd)
*** 3969,3975 ****
  	      /* Initialise the fields of the segment map.  Set the physical
  		 physical address to the LMA of the first section that has
  		 not yet been assigned.  */
- 
  	      m->next             = NULL;
  	      m->p_type           = p->p_type;
  	      m->p_flags          = p->p_flags;
--- 4064,4069 ----
*************** copy_private_bfd_data (ibfd, obfd)
*** 4000,4007 ****
  
    elf_tdata (obfd)->segment_map = mfirst;
  
  #if 0
!   /* Final Step: Sort the segments into ascending order of physical address. */
    if (mfirst != NULL)
      {
        struct elf_segment_map* prev;
--- 4094,4115 ----
  
    elf_tdata (obfd)->segment_map = mfirst;
  
+   /* If we had to estimate the number of program headers that were
+      going to be needed, then check our estimate know and adjust
+      the offset if necessary.  */
+   if (phdr_adjust_seg != NULL)
+     {
+       unsigned int count;
+       
+       for (count = 0, m = mfirst; m != NULL; m = m->next)
+ 	count ++;
+ 
+       if (count > phdr_adjust_num)
+ 	phdr_adjust_seg->p_paddr -= (count - phdr_adjust_num) * iehdr->e_phentsize;
+     }
+   
  #if 0
!   /* Final Step: Sort the segments into ascending order of physical address.  */
    if (mfirst != NULL)
      {
        struct elf_segment_map* prev;
*************** copy_private_bfd_data (ibfd, obfd)
*** 4009,4023 ****
        prev = mfirst;
        for (m = mfirst->next; m != NULL; prev = m, m = m->next)
  	{
! 	  /* Yes I know - its a bubble sort....*/
  	  if (m->next != NULL && (m->next->p_paddr < m->p_paddr))
  	    {
! 	      /* swap m and m->next */
  	      prev->next = m->next;
  	      m->next = m->next->next;
  	      prev->next->next = m;
  
! 	      /* restart loop. */
  	      m = mfirst;
  	    }
  	}
--- 4117,4131 ----
        prev = mfirst;
        for (m = mfirst->next; m != NULL; prev = m, m = m->next)
  	{
! 	  /* Yes I know - its a bubble sort....  */
  	  if (m->next != NULL && (m->next->p_paddr < m->p_paddr))
  	    {
! 	      /* swap m and m->next.  */
  	      prev->next = m->next;
  	      m->next = m->next->next;
  	      prev->next->next = m;
  
! 	      /* restart loop.  */
  	      m = mfirst;
  	    }
  	}

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