From e5242d4bede9761e9847ca85f8477b4e275a6e22 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 7 Nov 2014 20:29:43 +1030 Subject: [PATCH] tekhex buffer management and symbol types 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 ): 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. --- bfd/ChangeLog | 16 +++++++++ bfd/tekhex.c | 108 ++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 79 insertions(+), 45 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a9c8c16..6953e91 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,21 @@ 2014-11-07 Alan Modra + * tekhex.c (CHUNK_SPAN): Define. + (struct data_struct ): 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. + +2014-11-07 Alan Modra + * aoutx.h (aout_get_external_symbols): Tidy allocation of symbol buffer. 2014-11-07 Alan Modra 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; -- 2.7.4