diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 52 | ||||
-rw-r--r-- | bfd/aout-adobe.c | 1 | ||||
-rw-r--r-- | bfd/aout-target.h | 3 | ||||
-rw-r--r-- | bfd/aout-tic30.c | 3 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 9 | ||||
-rw-r--r-- | bfd/bfd.c | 3 | ||||
-rw-r--r-- | bfd/binary.c | 1 | ||||
-rw-r--r-- | bfd/bout.c | 1 | ||||
-rw-r--r-- | bfd/coff-alpha.c | 1 | ||||
-rw-r--r-- | bfd/coff-mips.c | 3 | ||||
-rw-r--r-- | bfd/coffcode.h | 4 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 3 | ||||
-rw-r--r-- | bfd/elf.c | 12 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 5 | ||||
-rw-r--r-- | bfd/i386msdos.c | 1 | ||||
-rw-r--r-- | bfd/i386os9k.c | 1 | ||||
-rw-r--r-- | bfd/ieee.c | 1 | ||||
-rw-r--r-- | bfd/ihex.c | 1 | ||||
-rw-r--r-- | bfd/libbfd-in.h | 9 | ||||
-rw-r--r-- | bfd/libbfd.h | 12 | ||||
-rw-r--r-- | bfd/merge.c | 465 | ||||
-rw-r--r-- | bfd/nlm-target.h | 3 | ||||
-rw-r--r-- | bfd/oasys.c | 1 | ||||
-rw-r--r-- | bfd/ppcboot.c | 1 | ||||
-rw-r--r-- | bfd/reloc.c | 22 | ||||
-rw-r--r-- | bfd/som.c | 1 | ||||
-rw-r--r-- | bfd/srec.c | 1 | ||||
-rw-r--r-- | bfd/targets.c | 6 | ||||
-rw-r--r-- | bfd/tekhex.c | 1 | ||||
-rw-r--r-- | bfd/versados.c | 1 | ||||
-rw-r--r-- | bfd/vms.c | 13 | ||||
-rw-r--r-- | bfd/xcoff-target.h | 1 |
32 files changed, 565 insertions, 77 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index afb0e26..c2bb974 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,55 @@ +2001-05-11 Jakub Jelinek <jakub@redhat.com> + + * merge.c (struct sec_merge_hash_entry): Add u.entsize and u.suffix + fields, change sec into secinfo. + (struct sec_merge_info): Add chain, remove last fields. + (struct sec_merge_sec_info): Add next, sec, psecinfo fields. + (sec_merge_hash_lookup): If lookup could not use a string only + because it has bad alignment, mark the old string for deletion. + (sec_merge_add): Add secinfo argument. Don't compute entry's + position, instead record the section. + (sec_merge_emit): Update for the sec into secinfo change in + struct sec_merge_hash_entry. + (_bfd_merge_section): Only record the section for merging, defer + putting strings into the hash table. + (cmplengthentry, last4_eq, last_eq, record_section, merge_strings, + _bfd_merge_sections): New functions. + (_bfd_merged_section_offset): Update for the sec_merge_hash_entry + changes. + * libbfd-in.h (_bfd_merge_sections): Add prototype. + (_bfd_nolink_bfd_merge_sections): Define. + * libbfd.h: Likewise. + (bfd_generic_merge_sections): Add prototype. + * targets.c (BFD_JUMP_TABLE_LINK): Add _bfd_merge_sections. + (struct bfd_target): Likewise. + * bfd.c (bfd_merge_sections): Define. + * bfd-in2.h: Rebuilt. + * elf.c (_bfd_elf_merge_sections): New function. + * elf-bfd.h (_bfd_elf_merge_sections): Add prototype. + * elfxx-target.h (bfd_elfNN_bfd_merge_sections): Define. + * reloc.c (bfd_generic_merge_sections): New function. + * vms.c (vms_bfd_merge_sections): New function. + * aout-adobe.c (aout_32_bfd_merge_sections): Define. + * aout-target.h (MY_bfd_merge_sections): Define. + * aout-tic30.c (MY_bfd_merge_sections): Define. + * binary.c (binary_bfd_merge_sections): Define. + * bout.c (b_out_bfd_merge_sections): Define. + * coff-alpha.c (_bfd_ecoff_bfd_merge_sections): Define. + * coffcode.c (coff_bfd_merge_sections): Define. + * coff-mips.c (_bfd_ecoff_bfd_merge_sections): Define. + * i386msdos.c (msdos_bfd_merge_sections): Define. + * i386os9k.c (os9k_bfd_merge_sections): Define. + * ieee.c (ieee_bfd_merge_sections): Define. + * ihex.c (ihex_bfd_merge_sections): Define. + * nlm-target.h (nlm_bfd_merge_sections): Define. + * oasys.c (oasys_bfd_merge_sections): Define. + * ppcboot.c (ppcboot_bfd_merge_sections): Define. + * som.c (som_bfd_merge_sections): Define. + * srec.c (srec_bfd_merge_sections): Define. + * tekhex.c (tekhex_bfd_merge_sections): Define. + * versados.c (versados_bfd_merge_sections): Define. + * xcoff-target.h (_bfd_xcoff_bfd_merge_sections): Define. + 2001-05-11 Nick Clifton <nickc@cambridge.redhat.com> * dwarf1.c (_bfd_dwarf1_find_nearest_line): Change type of 'addr' diff --git a/bfd/aout-adobe.c b/bfd/aout-adobe.c index 03acacb..e7c9fc9 100644 --- a/bfd/aout-adobe.c +++ b/bfd/aout-adobe.c @@ -513,6 +513,7 @@ aout_adobe_sizeof_headers (ignore_abfd, ignore) #define aout_32_get_section_contents_in_window _bfd_generic_get_section_contents_in_window #define aout_32_bfd_relax_section bfd_generic_relax_section #define aout_32_bfd_gc_sections bfd_generic_gc_sections +#define aout_32_bfd_merge_sections bfd_generic_merge_sections #define aout_32_bfd_link_hash_table_create \ _bfd_generic_link_hash_table_create #define aout_32_bfd_link_add_symbols _bfd_generic_link_add_symbols diff --git a/bfd/aout-target.h b/bfd/aout-target.h index 1b8d3a5..2d1e289 100644 --- a/bfd/aout-target.h +++ b/bfd/aout-target.h @@ -507,6 +507,9 @@ MY_bfd_final_link (abfd, info) #ifndef MY_bfd_gc_sections #define MY_bfd_gc_sections bfd_generic_gc_sections #endif +#ifndef MY_bfd_merge_sections +#define MY_bfd_merge_sections bfd_generic_merge_sections +#endif #ifndef MY_bfd_reloc_type_lookup #define MY_bfd_reloc_type_lookup NAME(aout,reloc_type_lookup) #endif diff --git a/bfd/aout-tic30.c b/bfd/aout-tic30.c index a3e977d..d02cf0d 100644 --- a/bfd/aout-tic30.c +++ b/bfd/aout-tic30.c @@ -940,6 +940,9 @@ tic30_aout_set_arch_mach (abfd, arch, machine) #ifndef MY_bfd_gc_sections #define MY_bfd_gc_sections bfd_generic_gc_sections #endif +#ifndef MY_bfd_merge_sections +#define MY_bfd_merge_sections bfd_generic_merge_sections +#endif #ifndef MY_bfd_reloc_type_lookup #define MY_bfd_reloc_type_lookup tic30_aout_reloc_type_lookup #endif diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 230b24a..bce9c0e 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3229,6 +3229,9 @@ bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); #define bfd_gc_sections(abfd, link_info) \ BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) +#define bfd_merge_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) + #define bfd_link_hash_table_create(abfd) \ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) @@ -3525,7 +3528,8 @@ CAT(NAME,_bfd_link_hash_table_create),\ CAT(NAME,_bfd_link_add_symbols),\ CAT(NAME,_bfd_final_link),\ CAT(NAME,_bfd_link_split_section),\ -CAT(NAME,_bfd_gc_sections) +CAT(NAME,_bfd_gc_sections),\ +CAT(NAME,_bfd_merge_sections) int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, @@ -3552,6 +3556,9 @@ CAT(NAME,_bfd_gc_sections) /* Remove sections that are not referenced from the output. */ boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); + /* Attempt to merge SEC_MERGE sections. */ + boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *)); + /* Routines to handle dynamic symbols and relocs. */ #define BFD_JUMP_TABLE_DYNAMIC(NAME)\ CAT(NAME,_get_dynamic_symtab_upper_bound),\ @@ -1126,6 +1126,9 @@ DESCRIPTION .#define bfd_gc_sections(abfd, link_info) \ . BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) . +.#define bfd_merge_sections(abfd, link_info) \ +. BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) +. .#define bfd_link_hash_table_create(abfd) \ . BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) . diff --git a/bfd/binary.c b/bfd/binary.c index a008f90..7fd01b3 100644 --- a/bfd/binary.c +++ b/bfd/binary.c @@ -345,6 +345,7 @@ binary_sizeof_headers (abfd, exec) bfd_generic_get_relocated_section_contents #define binary_bfd_relax_section bfd_generic_relax_section #define binary_bfd_gc_sections bfd_generic_gc_sections +#define binary_bfd_merge_sections bfd_generic_merge_sections #define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define binary_bfd_link_add_symbols _bfd_generic_link_add_symbols #define binary_bfd_final_link _bfd_generic_final_link @@ -1436,6 +1436,7 @@ b_out_bfd_get_relocated_section_contents (output_bfd, link_info, link_order, #define b_out_bfd_final_link _bfd_generic_final_link #define b_out_bfd_link_split_section _bfd_generic_link_split_section #define b_out_bfd_gc_sections bfd_generic_gc_sections +#define b_out_bfd_merge_sections bfd_generic_merge_sections #define aout_32_get_section_contents_in_window \ _bfd_generic_get_section_contents_in_window diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index b3cd0c7..d0db6a8 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -2359,6 +2359,7 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data = /* Relaxing sections is generic. */ #define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections +#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections const bfd_target ecoffalpha_little_vec = { diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c index ac16802..805824a 100644 --- a/bfd/coff-mips.c +++ b/bfd/coff-mips.c @@ -2600,6 +2600,9 @@ static const struct ecoff_backend_data mips_ecoff_backend_data = /* GC of sections is not done. */ #define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections +/* Merging of sections is not done. */ +#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections + extern const bfd_target ecoff_big_vec; const bfd_target ecoff_little_vec = diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 2cdc137..7415b96 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -5258,6 +5258,10 @@ static const bfd_coff_backend_data bfd_coff_std_swap_table = #define coff_bfd_gc_sections bfd_generic_gc_sections #endif +#ifndef coff_bfd_merge_sections +#define coff_bfd_merge_sections bfd_generic_merge_sections +#endif + #define CREATE_BIG_COFF_TARGET_VEC(VAR, NAME, EXTRA_O_FLAGS, EXTRA_S_FLAGS, UNDER, ALTERNATIVE) \ const bfd_target VAR = \ { \ diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index e1b61a2..fd3f347 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1006,6 +1006,9 @@ extern boolean _bfd_elf_link_hash_table_init const char *))); extern boolean _bfd_elf_slurp_version_tables PARAMS ((bfd *)); +extern boolean _bfd_elf_merge_sections + PARAMS ((bfd *, struct bfd_link_info *)); + extern boolean _bfd_elf_copy_private_symbol_data PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); extern boolean _bfd_elf_copy_private_section_data @@ -558,6 +558,18 @@ bfd_elf_generic_reloc (abfd, return bfd_reloc_continue; } +/* Finish SHF_MERGE section merging. */ + +boolean +_bfd_elf_merge_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (elf_hash_table (info)->merge_info) + _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info); + return true; +} + /* Print out the program headers. */ boolean diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 782b5da..8c39a4a 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -111,6 +111,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define bfd_elfNN_bfd_gc_sections _bfd_elfNN_gc_sections #endif +#ifndef bfd_elfNN_bfd_merge_sections +#define bfd_elfNN_bfd_merge_sections \ + _bfd_elf_merge_sections +#endif + #define bfd_elfNN_bfd_make_debug_symbol \ ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) diff --git a/bfd/i386msdos.c b/bfd/i386msdos.c index c42f365..91e4d9d 100644 --- a/bfd/i386msdos.c +++ b/bfd/i386msdos.c @@ -170,6 +170,7 @@ msdos_set_section_contents (abfd, section, location, offset, count) bfd_generic_get_relocated_section_contents #define msdos_bfd_relax_section bfd_generic_relax_section #define msdos_bfd_gc_sections bfd_generic_gc_sections +#define msdos_bfd_merge_sections bfd_generic_merge_sections #define msdos_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define msdos_bfd_link_add_symbols _bfd_generic_link_add_symbols #define msdos_bfd_final_link _bfd_generic_final_link diff --git a/bfd/i386os9k.c b/bfd/i386os9k.c index 7122479..5f6a5a3 100644 --- a/bfd/i386os9k.c +++ b/bfd/i386os9k.c @@ -328,6 +328,7 @@ os9k_sizeof_headers (ignore_abfd, ignore) bfd_generic_get_relocated_section_contents #define os9k_bfd_relax_section bfd_generic_relax_section #define os9k_bfd_gc_sections bfd_generic_gc_sections +#define os9k_bfd_merge_sections bfd_generic_merge_sections #define os9k_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define os9k_bfd_link_add_symbols _bfd_generic_link_add_symbols #define os9k_bfd_final_link _bfd_generic_final_link @@ -3926,6 +3926,7 @@ ieee_bfd_debug_info_accumulate (abfd, section) bfd_generic_get_relocated_section_contents #define ieee_bfd_relax_section bfd_generic_relax_section #define ieee_bfd_gc_sections bfd_generic_gc_sections +#define ieee_bfd_merge_sections bfd_generic_merge_sections #define ieee_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define ieee_bfd_link_add_symbols _bfd_generic_link_add_symbols #define ieee_bfd_final_link _bfd_generic_final_link @@ -983,6 +983,7 @@ ihex_sizeof_headers (abfd, exec) bfd_generic_get_relocated_section_contents #define ihex_bfd_relax_section bfd_generic_relax_section #define ihex_bfd_gc_sections bfd_generic_gc_sections +#define ihex_bfd_merge_sections bfd_generic_merge_sections #define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols #define ihex_bfd_final_link _bfd_generic_final_link diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index dae7635..14a4c1b 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -323,6 +323,10 @@ extern boolean _bfd_generic_set_section_contents ((boolean (*) \ PARAMS ((bfd *, struct bfd_link_info *))) \ bfd_false) +#define _bfd_nolink_bfd_merge_sections \ + ((boolean (*) \ + PARAMS ((bfd *, struct bfd_link_info *))) \ + bfd_false) #define _bfd_nolink_bfd_link_hash_table_create \ ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr) #define _bfd_nolink_bfd_link_add_symbols \ @@ -467,6 +471,11 @@ extern bfd_vma _bfd_stab_section_offset extern boolean _bfd_merge_section PARAMS ((bfd *, PTR *, asection *, PTR *)); +/* Attempt to merge SEC_MERGE sections. */ + +extern boolean _bfd_merge_sections + PARAMS ((bfd *, PTR)); + /* Write out a merged section. */ extern boolean _bfd_write_merged_section diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 675a6a1..9ce8e57 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -323,6 +323,10 @@ extern boolean _bfd_generic_set_section_contents ((boolean (*) \ PARAMS ((bfd *, struct bfd_link_info *))) \ bfd_false) +#define _bfd_nolink_bfd_merge_sections \ + ((boolean (*) \ + PARAMS ((bfd *, struct bfd_link_info *))) \ + bfd_false) #define _bfd_nolink_bfd_link_hash_table_create \ ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr) #define _bfd_nolink_bfd_link_add_symbols \ @@ -467,6 +471,11 @@ extern bfd_vma _bfd_stab_section_offset extern boolean _bfd_merge_section PARAMS ((bfd *, PTR *, asection *, PTR *)); +/* Attempt to merge SEC_MERGE sections. */ + +extern boolean _bfd_merge_sections + PARAMS ((bfd *, PTR)); + /* Write out a merged section. */ extern boolean _bfd_write_merged_section @@ -1080,6 +1089,9 @@ bfd_generic_relax_section PARAMS ((bfd *abfd, boolean bfd_generic_gc_sections PARAMS ((bfd *, struct bfd_link_info *)); +boolean +bfd_generic_merge_sections PARAMS ((bfd *, struct bfd_link_info *)); + bfd_byte * bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, struct bfd_link_info *link_info, diff --git a/bfd/merge.c b/bfd/merge.c index 6619dcd..3d09041 100644 --- a/bfd/merge.c +++ b/bfd/merge.c @@ -24,9 +24,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "libbfd.h" +#include "hashtab.h" #include <ctype.h> +struct sec_merge_sec_info; + /* An entry in the section merge hash table. */ struct sec_merge_hash_entry @@ -37,10 +40,16 @@ struct sec_merge_hash_entry /* Start of this string needs to be aligned to alignment octets (not 1 << align). */ unsigned int alignment; - /* Index within the merged section. */ - bfd_size_type index; + union { + /* Index within the merged section. */ + bfd_size_type index; + /* Entity size (if present in suffix hash tables). */ + unsigned int entsize; + /* Entry this is a suffix of (if alignment is 0). */ + struct sec_merge_hash_entry *suffix; + } u; /* Which section is it in. */ - asection *sec; + struct sec_merge_sec_info *secinfo; /* Next entity in the hash table. */ struct sec_merge_hash_entry *next; }; @@ -66,14 +75,20 @@ struct sec_merge_info { /* Chain of sec_merge_infos. */ struct sec_merge_info *next; + /* Chain of sec_merge_sec_infos. */ + struct sec_merge_sec_info *chain; /* A hash table used to hold section content. */ struct sec_merge_hash *htab; - /* The last section attempted for merge. */ - asection *last; }; struct sec_merge_sec_info { + /* Chain of sec_merge_sec_infos. */ + struct sec_merge_sec_info *next; + /* The corresponding section. */ + asection *sec; + /* Pointer to merge_info pointing to us. */ + PTR *psecinfo; /* A hash table used to hold section content. */ struct sec_merge_hash *htab; /* First string in this section. */ @@ -89,7 +104,8 @@ static struct sec_merge_hash_entry *sec_merge_hash_lookup static struct sec_merge_hash *sec_merge_init PARAMS ((unsigned int, boolean)); static struct sec_merge_hash_entry *sec_merge_add - PARAMS ((struct sec_merge_hash *, const char *, unsigned int)); + PARAMS ((struct sec_merge_hash *, const char *, unsigned int, + struct sec_merge_sec_info *)); static boolean sec_merge_emit PARAMS ((bfd *, struct sec_merge_hash_entry *)); @@ -118,9 +134,9 @@ sec_merge_hash_newfunc (entry, table, string) if (ret) { /* Initialize the local fields. */ - ret->index = (bfd_size_type) -1; + ret->u.suffix = NULL; ret->alignment = 0; - ret->sec = NULL; + ret->secinfo = NULL; ret->next = NULL; } @@ -202,11 +218,14 @@ sec_merge_hash_lookup (table, string, alignment, create) && memcmp (hashp->root.string, string, len) == 0) { /* If the string we found does not have at least the required - alignment, we need to insert another copy. - FIXME: The old copy could be removed and the space allocated - for it filled by some new string (similarly with padding). */ + alignment, we need to insert another copy. */ if (hashp->alignment < alignment) - break; + { + /* Mark the less aligned copy as deleted. */ + hashp->len = 0; + hashp->alignment = 0; + break; + } return hashp; } } @@ -262,10 +281,11 @@ sec_merge_init (entsize, strings) already present. */ static struct sec_merge_hash_entry * -sec_merge_add (tab, str, alignment) +sec_merge_add (tab, str, alignment, secinfo) struct sec_merge_hash *tab; const char *str; unsigned int alignment; + struct sec_merge_sec_info *secinfo; { register struct sec_merge_hash_entry *entry; @@ -273,11 +293,10 @@ sec_merge_add (tab, str, alignment) if (entry == NULL) return NULL; - if (entry->index == (bfd_size_type) -1) + if (entry->secinfo == NULL) { - tab->size = (tab->size + alignment - 1) & ~((bfd_vma) alignment - 1); - entry->index = tab->size; - tab->size += entry->len; + tab->size++; + entry->secinfo = secinfo; if (tab->first == NULL) tab->first = entry; else @@ -293,7 +312,8 @@ sec_merge_emit (abfd, entry) register bfd *abfd; struct sec_merge_hash_entry *entry; { - asection *sec = entry->sec; + struct sec_merge_sec_info *secinfo = entry->secinfo; + asection *sec = secinfo->sec; char *pad = ""; bfd_size_type off = 0; int alignment_power = bfd_get_section_alignment (abfd, sec->output_section); @@ -301,7 +321,7 @@ sec_merge_emit (abfd, entry) if (alignment_power) pad = bfd_zmalloc (1 << alignment_power); - for (; entry != NULL && entry->sec == sec; entry = entry->next) + for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) { register const char *str; register size_t len; @@ -327,7 +347,7 @@ sec_merge_emit (abfd, entry) if (alignment_power) free (pad); - return entry == NULL || entry->sec != sec; + return entry == NULL || entry->secinfo != secinfo; } /* This function is called for each input file from the add_symbols @@ -340,15 +360,12 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) asection *sec; PTR *psecinfo; { - boolean first, nul; struct sec_merge_info *sinfo; struct sec_merge_sec_info *secinfo; - unsigned char *p, *end; - bfd_vma mask, eltalign; unsigned int align; - unsigned int i; if (sec->_raw_size == 0 + || (sec->flags & SEC_EXCLUDE) || (sec->flags & SEC_MERGE) == 0 || sec->entsize == 0) return true; @@ -367,7 +384,7 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) return true; } - align = bfd_get_section_alignment (abfd, sec); + align = bfd_get_section_alignment (sec->owner, sec); if ((sec->entsize < (unsigned int)(1 << align) && ((sec->entsize & (sec->entsize - 1)) || !(sec->flags & SEC_STRINGS))) @@ -383,23 +400,22 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) return true; } - first = false; - for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next) - if (! ((sinfo->last->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS)) - && sinfo->last->entsize == sec->entsize - && ! strcmp (sinfo->last->name, sec->name)) + if ((secinfo = sinfo->chain) + && ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS)) + && secinfo->sec->entsize == sec->entsize + && ! strcmp (secinfo->sec->name, sec->name)) break; if (sinfo == NULL) { /* Initialize the information we need to keep track of. */ - first = true; sinfo = (struct sec_merge_info *) bfd_alloc (abfd, sizeof (struct sec_merge_info)); if (sinfo == NULL) goto error_return; sinfo->next = (struct sec_merge_info *) *psinfo; + sinfo->chain = NULL; *psinfo = (PTR) sinfo; sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS)); @@ -415,14 +431,121 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) goto error_return; secinfo = (struct sec_merge_sec_info *)*psecinfo; + if (sinfo->chain) + { + secinfo->next = sinfo->chain->next; + sinfo->chain->next = secinfo; + } + else + secinfo->next = secinfo; + sinfo->chain = secinfo; + secinfo->sec = sec; + secinfo->psecinfo = psecinfo; secinfo->htab = sinfo->htab; - sinfo->htab->size = 0; secinfo->first = NULL; - if (! bfd_get_section_contents (abfd, sec, secinfo->contents, 0, + if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, 0, sec->_raw_size)) goto error_return; + return true; + + error_return: + *psecinfo = NULL; + return false; +} + +/* Compare two sec_merge_hash_entry structures. This is called via qsort. */ + +static int +cmplengthentry (a, b) + const PTR a; + const PTR b; +{ + struct sec_merge_hash_entry * A = *(struct sec_merge_hash_entry **) a; + struct sec_merge_hash_entry * B = *(struct sec_merge_hash_entry **) b; + + if (A->len < B->len) + return 1; + else if (A->len > B->len) + return -1; + + return memcmp (A->root.string, B->root.string, A->len); +} + +static int +last4_eq (a, b) + const void *a, *b; +{ + struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a; + struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b; + + if (memcmp (A->root.string + A->len - 5 * A->u.entsize, + B->root.string + B->len - 5 * A->u.entsize, + 4 * A->u.entsize) != 0) + /* This was a hashtable collision. */ + return 0; + + if (A->len <= B->len) + /* B cannot be a suffix of A unless A is equal to B, which is guaranteed + not to be equal by the hash table. */ + return 0; + + if (A->alignment < B->alignment + || ((A->len - B->len) & (B->alignment - 1))) + /* The suffix is not sufficiently aligned. */ + return 0; + + return memcmp (A->root.string + (A->len - B->len), + B->root.string, B->len - 5 * A->u.entsize) == 0; +} + +static int +last_eq (a, b) + const void *a, *b; +{ + struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a; + struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b; + + if (B->len >= 5 * A->u.entsize) + /* Longer strings are just pushed into the hash table, + they'll be used when looking up for very short strings. */ + return 0; + + if (memcmp (A->root.string + A->len - 2 * A->u.entsize, + B->root.string + B->len - 2 * A->u.entsize, + A->u.entsize) != 0) + /* This was a hashtable collision. */ + return 0; + + if (A->len <= B->len) + /* B cannot be a suffix of A unless A is equal to B, which is guaranteed + not to be equal by the hash table. */ + return 0; + + if (A->alignment < B->alignment + || ((A->len - B->len) & (B->alignment - 1))) + /* The suffix is not sufficiently aligned. */ + return 0; + + return memcmp (A->root.string + (A->len - B->len), + B->root.string, B->len - 2 * A->u.entsize) == 0; +} + +/* Record one section into the hash table. */ +static boolean +record_section (sinfo, secinfo) + struct sec_merge_info *sinfo; + struct sec_merge_sec_info *secinfo; +{ + asection *sec = secinfo->sec; + struct sec_merge_hash_entry *entry; + boolean nul; + unsigned char *p, *end; + bfd_vma mask, eltalign; + unsigned int align, i; + + align = bfd_get_section_alignment (sec->owner, sec); end = secinfo->contents + sec->_raw_size; nul = false; mask = ((bfd_vma)1 << align) - 1; @@ -430,19 +553,13 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) { for (p = secinfo->contents; p < end;) { - struct sec_merge_hash_entry *entry; - eltalign = p - secinfo->contents; eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1; if (!eltalign || eltalign > mask) eltalign = mask + 1; - entry = sec_merge_add (sinfo->htab, p, eltalign); - if (entry->sec == NULL) - { - if (secinfo->first == NULL) - secinfo->first = entry; - entry->sec = sec; - } + entry = sec_merge_add (sinfo->htab, p, eltalign, secinfo); + if (! entry) + goto error_return; p += entry->len; if (sec->entsize == 1) { @@ -451,13 +568,10 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) if (!nul && !((p - secinfo->contents) & mask)) { nul = true; - entry = sec_merge_add (sinfo->htab, "", mask + 1); - if (entry->sec == NULL) - { - if (secinfo->first == NULL) - secinfo->first = entry; - entry->sec = sec; - } + entry = sec_merge_add (sinfo->htab, "", mask + 1, + secinfo); + if (! entry) + goto error_return; } p++; } @@ -474,13 +588,10 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) if (!nul && !((p - secinfo->contents) & mask)) { nul = true; - entry = sec_merge_add (sinfo->htab, p, mask + 1); - if (entry->sec == NULL) - { - if (secinfo->first == NULL) - secinfo->first = entry; - entry->sec = sec; - } + entry = sec_merge_add (sinfo->htab, p, mask + 1, + secinfo); + if (! entry) + goto error_return; } p += sec->entsize; } @@ -491,29 +602,235 @@ _bfd_merge_section (abfd, psinfo, sec, psecinfo) { for (p = secinfo->contents; p < end; p += sec->entsize) { - struct sec_merge_hash_entry *entry; + entry = sec_merge_add (sinfo->htab, p, 1, secinfo); + if (! entry) + goto error_return; + } + } + + return true; + +error_return: + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + *secinfo->psecinfo = NULL; + return false; +} + +/* This is a helper function for _bfd_merge_sections. It attempts to + merge strings matching suffixes of longer strings. */ +static void +merge_strings (sinfo) + struct sec_merge_info *sinfo; +{ + struct sec_merge_hash_entry **array, **a, **end, *e; + struct sec_merge_sec_info *secinfo; + htab_t lasttab = NULL, last4tab = NULL; + bfd_size_type size; + + /* Now sort the strings by length, longest first. */ + array = (struct sec_merge_hash_entry **) + malloc (sinfo->htab->size + * sizeof (struct sec_merge_hash_entry *)); + if (array == NULL) + goto alloc_failure; + + for (e = sinfo->htab->first, a = array; e; e = e->next) + if (e->alignment) + *a++ = e; + + sinfo->htab->size = a - array; - entry = sec_merge_add (sinfo->htab, p, 1); - if (entry->sec == NULL) + qsort (array, sinfo->htab->size, sizeof (struct sec_merge_hash_entry *), + cmplengthentry); + + last4tab = htab_create (sinfo->htab->size * 4, NULL, last4_eq, NULL); + lasttab = htab_create (sinfo->htab->size * 4, NULL, last_eq, NULL); + if (lasttab == NULL || last4tab == NULL) + goto alloc_failure; + + /* Now insert the strings into hash tables (strings with last 4 characters + and strings with last character equal), look for longer strings which + we're suffix of. */ + for (a = array, end = array + sinfo->htab->size; a < end; a++) + { + register hashval_t hash; + unsigned int c; + unsigned int i; + const unsigned char *s; + PTR *p; + + e = *a; + e->u.entsize = sinfo->htab->entsize; + if (e->len <= e->u.entsize) + break; + if (e->len > 4 * e->u.entsize) + { + s = e->root.string + e->len - e->u.entsize; + hash = 0; + for (i = 0; i < 4 * e->u.entsize; i++) { - if (secinfo->first == NULL) - secinfo->first = entry; - entry->sec = sec; + c = *--s; + hash += c + (c << 17); + hash ^= hash >> 2; + } + p = htab_find_slot_with_hash (last4tab, e, hash, INSERT); + if (p == NULL) + goto alloc_failure; + if (*p) + { + struct sec_merge_hash_entry *ent; + + ent = (struct sec_merge_hash_entry *) *p; + e->u.suffix = ent; + e->alignment = 0; + continue; } + else + *p = (PTR) e; + } + s = e->root.string + e->len - e->u.entsize; + hash = 0; + for (i = 0; i < e->u.entsize; i++) + { + c = *--s; + hash += c + (c << 17); + hash ^= hash >> 2; + } + p = htab_find_slot_with_hash (lasttab, e, hash, INSERT); + if (p == NULL) + goto alloc_failure; + if (*p) + { + struct sec_merge_hash_entry *ent; + + ent = (struct sec_merge_hash_entry *) *p; + e->u.suffix = ent; + e->alignment = 0; } + else + *p = (PTR) e; } - sec->_cooked_size = sinfo->htab->size; - if (!sec->_cooked_size) - sec->flags |= SEC_EXCLUDE; - sinfo->last = sec; - return true; +alloc_failure: + if (array) + free (array); + if (lasttab) + htab_delete (lasttab); + if (last4tab) + htab_delete (last4tab); + + /* Now assign positions to the strings we want to keep. */ + size = 0; + secinfo = sinfo->htab->first->secinfo; + for (e = sinfo->htab->first; e; e = e->next) + { + if (e->secinfo != secinfo) + { + secinfo->sec->_cooked_size = size; + secinfo = e->secinfo; + } + if (e->alignment) + { + if (e->secinfo->first == NULL) + { + e->secinfo->first = e; + size = 0; + } + size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); + e->u.index = size; + size += e->len; + } + } + secinfo->sec->_cooked_size = size; + + /* And now adjust the rest, removing them from the chain (but not hashtable) + at the same time. */ + for (a = &sinfo->htab->first, e = *a; e; e = e->next) + if (e->alignment) + a = &e->next; + else + { + *a = e->next; + if (e->len) + { + e->secinfo = e->u.suffix->secinfo; + e->alignment = e->u.suffix->alignment; + e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); + } + } +} - error_return: - if (*psecinfo != NULL) - free (*psecinfo); - *psecinfo = NULL; - return false; +/* This function is called once after all SEC_MERGE sections are registered + with _bfd_merge_section. */ + +boolean +_bfd_merge_sections (abfd, xsinfo) + bfd *abfd ATTRIBUTE_UNUSED; + PTR xsinfo; +{ + struct sec_merge_info *sinfo; + + for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) + { + struct sec_merge_sec_info * secinfo; + + if (! sinfo->chain) + continue; + + /* Move sinfo->chain to head of the chain, terminate it. */ + secinfo = sinfo->chain; + sinfo->chain = secinfo->next; + secinfo->next = NULL; + + /* Record the sections into the hash table. */ + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + if (secinfo->sec->flags & SEC_EXCLUDE) + *secinfo->psecinfo = NULL; + else if (! record_section (sinfo, secinfo)) + break; + + if (secinfo) + continue; + + if (sinfo->htab->strings) + merge_strings (sinfo); + else + { + struct sec_merge_hash_entry *e; + bfd_size_type size = 0; + + /* Things are much simpler for non-strings. + Just assign them slots in the section. */ + secinfo = NULL; + for (e = sinfo->htab->first; e; e = e->next) + { + if (e->secinfo->first == NULL) + { + if (secinfo) + secinfo->sec->_cooked_size = size; + e->secinfo->first = e; + size = 0; + } + size = (size + e->alignment - 1) + & ~((bfd_vma) e->alignment - 1); + e->u.index = size; + size += e->len; + secinfo = e->secinfo; + } + secinfo->sec->_cooked_size = size; + } + + /* Finally shrink all input sections which have not made it into + the hash table at all. */ + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + if (secinfo->first == NULL) + { + secinfo->sec->_cooked_size = 0; + secinfo->sec->flags |= SEC_EXCLUDE; + } + } + + return true; } /* Write out the merged section. */ @@ -619,6 +936,6 @@ _bfd_merged_section_offset (output_bfd, psec, psecinfo, offset, addend) - entry->len; } - *psec = entry->sec; - return entry->index + (secinfo->contents + offset - p); + *psec = entry->secinfo->sec; + return entry->u.index + (secinfo->contents + offset - p); } diff --git a/bfd/nlm-target.h b/bfd/nlm-target.h index 02ba031..c1b086b 100644 --- a/bfd/nlm-target.h +++ b/bfd/nlm-target.h @@ -1,5 +1,5 @@ /* Target definitions for 32/64-bit NLM (NetWare Loadable Module) - Copyright 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc. + Copyright 1993, 1994, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -42,6 +42,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ bfd_generic_get_relocated_section_contents #define nlm_bfd_relax_section bfd_generic_relax_section #define nlm_bfd_gc_sections bfd_generic_gc_sections +#define nlm_bfd_merge_sections bfd_generic_merge_sections #define nlm_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define nlm_bfd_link_add_symbols _bfd_generic_link_add_symbols #define nlm_bfd_final_link _bfd_generic_final_link diff --git a/bfd/oasys.c b/bfd/oasys.c index 6552a1d..47e30cb 100644 --- a/bfd/oasys.c +++ b/bfd/oasys.c @@ -1476,6 +1476,7 @@ oasys_sizeof_headers (abfd, exec) bfd_generic_get_relocated_section_contents #define oasys_bfd_relax_section bfd_generic_relax_section #define oasys_bfd_gc_sections bfd_generic_gc_sections +#define oasys_bfd_merge_sections bfd_generic_merge_sections #define oasys_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define oasys_bfd_link_add_symbols _bfd_generic_link_add_symbols #define oasys_bfd_final_link _bfd_generic_final_link diff --git a/bfd/ppcboot.c b/bfd/ppcboot.c index b2250a0..eccbe79 100644 --- a/bfd/ppcboot.c +++ b/bfd/ppcboot.c @@ -475,6 +475,7 @@ ppcboot_bfd_print_private_bfd_data (abfd, farg) bfd_generic_get_relocated_section_contents #define ppcboot_bfd_relax_section bfd_generic_relax_section #define ppcboot_bfd_gc_sections bfd_generic_gc_sections +#define ppcboot_bfd_merge_sections bfd_generic_merge_sections #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols #define ppcboot_bfd_final_link _bfd_generic_final_link diff --git a/bfd/reloc.c b/bfd/reloc.c index 226d1e9..5823a23 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3254,6 +3254,28 @@ bfd_generic_gc_sections (abfd, link_info) /* INTERNAL_FUNCTION + bfd_generic_merge_sections + +SYNOPSIS + boolean bfd_generic_merge_sections + (bfd *, struct bfd_link_info *); + +DESCRIPTION + Provides default handling for SEC_MERGE section merging for back ends + which don't have SEC_MERGE support -- i.e., does nothing. +*/ + +/*ARGSUSED*/ +boolean +bfd_generic_merge_sections (abfd, link_info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; +{ + return true; +} + +/* +INTERNAL_FUNCTION bfd_generic_get_relocated_section_contents SYNOPSIS @@ -6286,6 +6286,7 @@ som_bfd_link_split_section (abfd, sec) #define som_bfd_final_link _bfd_generic_final_link #define som_bfd_gc_sections bfd_generic_gc_sections +#define som_bfd_merge_sections bfd_generic_merge_sections const bfd_target som_vec = { "som", /* name */ @@ -1262,6 +1262,7 @@ srec_print_symbol (ignore_abfd, afile, symbol, how) bfd_generic_get_relocated_section_contents #define srec_bfd_relax_section bfd_generic_relax_section #define srec_bfd_gc_sections bfd_generic_gc_sections +#define srec_bfd_merge_sections bfd_generic_merge_sections #define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols #define srec_bfd_final_link _bfd_generic_final_link diff --git a/bfd/targets.c b/bfd/targets.c index 0e2ca4d..c46ecc3 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -416,7 +416,8 @@ BFD_JUMP_TABLE macros. .CAT(NAME,_bfd_link_add_symbols),\ .CAT(NAME,_bfd_final_link),\ .CAT(NAME,_bfd_link_split_section),\ -.CAT(NAME,_bfd_gc_sections) +.CAT(NAME,_bfd_gc_sections),\ +.CAT(NAME,_bfd_merge_sections) . int (*_bfd_sizeof_headers) PARAMS ((bfd *, boolean)); . bfd_byte * (*_bfd_get_relocated_section_contents) PARAMS ((bfd *, . struct bfd_link_info *, struct bfd_link_order *, @@ -443,6 +444,9 @@ BFD_JUMP_TABLE macros. . {* Remove sections that are not referenced from the output. *} . boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); . +. {* Attempt to merge SEC_MERGE sections. *} +. boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *)); +. . {* Routines to handle dynamic symbols and relocs. *} .#define BFD_JUMP_TABLE_DYNAMIC(NAME)\ .CAT(NAME,_get_dynamic_symtab_upper_bound),\ diff --git a/bfd/tekhex.c b/bfd/tekhex.c index ccfe7d8..13ce00e 100644 --- a/bfd/tekhex.c +++ b/bfd/tekhex.c @@ -1001,6 +1001,7 @@ tekhex_print_symbol (ignore_abfd, filep, symbol, how) bfd_generic_get_relocated_section_contents #define tekhex_bfd_relax_section bfd_generic_relax_section #define tekhex_bfd_gc_sections bfd_generic_gc_sections +#define tekhex_bfd_merge_sections bfd_generic_merge_sections #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols #define tekhex_bfd_final_link _bfd_generic_final_link diff --git a/bfd/versados.c b/bfd/versados.c index 04df49a..e281d71 100644 --- a/bfd/versados.c +++ b/bfd/versados.c @@ -840,6 +840,7 @@ versados_canonicalize_reloc (abfd, section, relptr, symbols) bfd_generic_get_relocated_section_contents #define versados_bfd_relax_section bfd_generic_relax_section #define versados_bfd_gc_sections bfd_generic_gc_sections +#define versados_bfd_merge_sections bfd_generic_merge_sections #define versados_bfd_link_hash_table_create _bfd_generic_link_hash_table_create #define versados_bfd_link_add_symbols _bfd_generic_link_add_symbols #define versados_bfd_final_link _bfd_generic_final_link @@ -110,6 +110,8 @@ static boolean vms_bfd_relax_section boolean *again)); static boolean vms_bfd_gc_sections PARAMS ((bfd *abfd, struct bfd_link_info *link_info)); +static boolean vms_bfd_merge_sections + PARAMS ((bfd *abfd, struct bfd_link_info *link_info)); static struct bfd_link_hash_table *vms_bfd_link_hash_table_create PARAMS ((bfd *abfd)); static boolean vms_bfd_link_add_symbols @@ -1784,6 +1786,17 @@ vms_bfd_gc_sections (abfd, link_info) return true; } +static boolean +vms_bfd_merge_sections (abfd, link_info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; +{ +#if VMS_DEBUG + vms_debug (1, "vms_bfd_merge_sections(%p, %p)\n", abfd, link_info); +#endif + return true; +} + /* Create a hash table for the linker. Different backends store different information in this table. */ diff --git a/bfd/xcoff-target.h b/bfd/xcoff-target.h index a3cc0c0..0787b8d 100644 --- a/bfd/xcoff-target.h +++ b/bfd/xcoff-target.h @@ -97,6 +97,7 @@ extern int lynx_core_file_failing_signal PARAMS ((bfd *abfd)); coff_bfd_get_relocated_section_contents #define _bfd_xcoff_bfd_relax_section coff_bfd_relax_section #define _bfd_xcoff_bfd_gc_sections coff_bfd_gc_sections +#define _bfd_xcoff_bfd_merge_sections coff_bfd_merge_sections #define _bfd_xcoff_bfd_link_split_section coff_bfd_link_split_section /* XCOFF archives do not have anything which corresponds to an |