tekhex buffer management and symbol types

Alan Modra amodra@gmail.com
Fri Nov 7 10:14:00 GMT 2014


On Fri, Nov 07, 2014 at 01:23:37PM +1030, Alan Modra wrote:
> In my opinion it is a complete waste of time rewriting
> tekhex.c to better deal with fuzzed input.

So I wasted some time..

Dramatically reduces memory consumption and processing time for large
all-zero data segments.  Allows multiple symbol types attached to a
given segment to survive objcopy.

	* tekhex.c (CHUNK_SPAN): Define.
	(struct data_struct <chunk_init>): Use one byte per span, update
	all code accessing this field.
	(find_chunk): Add create param, don't create new entry unless set.
	(insert_byte): Don't save zeros.
	(first_phase): Set section SEC_CODE or SEC_DATA flag depending
	on symbol type.  Create an alternate section if both types of
	symbol are given.  Attach type '2' and '6' symbols to absolute
	section.
	(move_section_contents): Fix caching of chunk.  Don't create chunk
	when reading, or for writing zeros.
	(tekhex_set_section_contents): Don't create initial chunks.
	(tekhex_write_object_contents): Use CHUNK_SPAN.

diff --git a/bfd/tekhex.c b/bfd/tekhex.c
index 2220d50..aaebcee 100644
--- a/bfd/tekhex.c
+++ b/bfd/tekhex.c
@@ -246,11 +246,12 @@ struct tekhex_data_list_struct
 typedef struct tekhex_data_list_struct tekhex_data_list_type;
 
 #define CHUNK_MASK 0x1fff
+#define CHUNK_SPAN 32
 
 struct data_struct
 {
-  char chunk_data[CHUNK_MASK + 1];
-  char chunk_init[CHUNK_MASK + 1];
+  unsigned char chunk_data[CHUNK_MASK + 1];
+  unsigned char chunk_init[(CHUNK_MASK + 1 + CHUNK_SPAN - 1) / CHUNK_SPAN];
   bfd_vma vma;
   struct data_struct *next;
 };
@@ -312,7 +313,7 @@ getsym (char *dstp, char **srcp, unsigned int *lenp)
 }
 
 static struct data_struct *
-find_chunk (bfd *abfd, bfd_vma vma)
+find_chunk (bfd *abfd, bfd_vma vma, bfd_boolean create)
 {
   struct data_struct *d = abfd->tdata.tekhex_data->data;
 
@@ -320,7 +321,7 @@ find_chunk (bfd *abfd, bfd_vma vma)
   while (d && (d->vma) != vma)
     d = d->next;
 
-  if (!d)
+  if (!d && create)
     {
       /* No chunk for this address, so make one up.  */
       d = (struct data_struct *)
@@ -339,11 +340,14 @@ find_chunk (bfd *abfd, bfd_vma vma)
 static void
 insert_byte (bfd *abfd, int value, bfd_vma addr)
 {
-  /* Find the chunk that this byte needs and put it in.  */
-  struct data_struct *d = find_chunk (abfd, addr);
+  if (value != 0)
+    {
+      /* Find the chunk that this byte needs and put it in.  */
+      struct data_struct *d = find_chunk (abfd, addr, TRUE);
 
-  d->chunk_data[addr & CHUNK_MASK] = value;
-  d->chunk_init[addr & CHUNK_MASK] = 1;
+      d->chunk_data[addr & CHUNK_MASK] = value;
+      d->chunk_init[(addr & CHUNK_MASK) / CHUNK_SPAN] = 1;
+    }
 }
 
 /* The first pass is to find the names of all the sections, and see
@@ -352,7 +356,7 @@ insert_byte (bfd *abfd, int value, bfd_vma addr)
 static bfd_boolean
 first_phase (bfd *abfd, int type, char *src)
 {
-  asection *section = bfd_abs_section_ptr;
+  asection *section, *alt_section;
   unsigned int len;
   bfd_vma val;
   char sym[17];			/* A symbol can only be 16chars long.  */
@@ -392,6 +396,7 @@ first_phase (bfd *abfd, int type, char *src)
 	  if (section == NULL)
 	    return FALSE;
 	}
+      alt_section = NULL;
       while (*src)
 	{
 	  switch (*src)
@@ -439,6 +444,42 @@ first_phase (bfd *abfd, int type, char *src)
 		  new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT);
 		else
 		  new_symbol->symbol.flags = BSF_LOCAL;
+		if (stype == '2' || stype == '6')
+		  new_symbol->symbol.section = bfd_abs_section_ptr;
+		else if (stype == '3' || stype == '7')
+		  {
+		    if ((section->flags & SEC_DATA) == 0)
+		      section->flags |= SEC_CODE;
+		    else
+		      {
+			if (alt_section == NULL)
+			  alt_section = bfd_get_next_section_by_name (section);
+			if (alt_section == NULL)
+			  alt_section = bfd_make_section_anyway_with_flags
+			    (abfd, section->name,
+			     (section->flags & ~SEC_DATA) | SEC_CODE);
+			if (alt_section == NULL)
+			  return FALSE;
+			new_symbol->symbol.section = alt_section;
+		      }
+		  }
+		else if (stype == '4' || stype == '8')
+		  {
+		    if ((section->flags & SEC_CODE) == 0)
+		      section->flags |= SEC_DATA;
+		    else
+		      {
+			if (alt_section == NULL)
+			  alt_section = bfd_get_next_section_by_name (section);
+			if (alt_section == NULL)
+			  alt_section = bfd_make_section_anyway_with_flags
+			    (abfd, section->name,
+			     (section->flags & ~SEC_CODE) | SEC_DATA);
+			if (alt_section == NULL)
+			  return FALSE;
+			new_symbol->symbol.section = alt_section;
+		      }
+		  }
 		if (!getvalue (&src, &val))
 		  return FALSE;
 		new_symbol->symbol.value = val - section->vma;
@@ -589,22 +630,26 @@ move_section_contents (bfd *abfd,
       /* Get high bits of address.  */
       bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK;
       bfd_vma low_bits = addr & CHUNK_MASK;
+      bfd_boolean must_write = !get && *location != 0;
 
-      if (chunk_number != prev_number)
-	/* Different chunk, so move pointer. */
-	d = find_chunk (abfd, chunk_number);
+      if (chunk_number != prev_number || (!d && must_write))
+	{
+	  /* Different chunk, so move pointer. */
+	  d = find_chunk (abfd, chunk_number, must_write);
+	  prev_number = chunk_number;
+	}
 
       if (get)
 	{
-	  if (d->chunk_init[low_bits])
+	  if (d)
 	    *location = d->chunk_data[low_bits];
 	  else
 	    *location = 0;
 	}
-      else
+      else if (must_write)
 	{
 	  d->chunk_data[low_bits] = *location;
-	  d->chunk_init[low_bits] = (*location != 0);
+	  d->chunk_init[low_bits / CHUNK_SPAN] = 1;
 	}
 
       location++;
@@ -644,24 +689,6 @@ tekhex_set_section_contents (bfd *abfd,
 			     file_ptr offset,
 			     bfd_size_type bytes_to_do)
 {
-  if (! abfd->output_has_begun)
-    {
-      /* The first time around, allocate enough sections to hold all the chunks.  */
-      asection *s = abfd->sections;
-      bfd_vma vma;
-
-      for (s = abfd->sections; s; s = s->next)
-	{
-	  if (s->flags & SEC_LOAD)
-	    {
-	      for (vma = s->vma & ~(bfd_vma) CHUNK_MASK;
-		   vma < s->vma + s->size;
-		   vma += CHUNK_MASK)
-		find_chunk (abfd, vma);
-	    }
-	}
-    }
-
   if (section->flags & (SEC_LOAD | SEC_ALLOC))
     {
       move_section_contents (abfd, section, locationp, offset, bytes_to_do,
@@ -772,26 +799,17 @@ tekhex_write_object_contents (bfd *abfd)
        d = d->next)
     {
       int low;
-
-      const int span = 32;
       int addr;
 
       /* Write it in blocks of 32 bytes.  */
-      for (addr = 0; addr < CHUNK_MASK + 1; addr += span)
+      for (addr = 0; addr < CHUNK_MASK + 1; addr += CHUNK_SPAN)
 	{
-	  int need = 0;
-
-	  /* Check to see if necessary.  */
-	  for (low = 0; !need && low < span; low++)
-	    if (d->chunk_init[addr + low])
-	      need = 1;
-
-	  if (need)
+	  if (d->chunk_init[addr / CHUNK_SPAN])
 	    {
 	      char *dst = buffer;
 
 	      writevalue (&dst, addr + d->vma);
-	      for (low = 0; low < span; low++)
+	      for (low = 0; low < CHUNK_SPAN; low++)
 		{
 		  TOHEX (dst, d->chunk_data[addr + low]);
 		  dst += 2;

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list