From 5315c42827694b2d9d25cf99f238de673fbe475c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 24 May 1994 20:44:50 +0000 Subject: [PATCH] Make MIPS ELF use new ELF backend linker. No shared library support yet. * elf32-mips.c (bfd_mips_elf32_swap_gptab_in): New function. (bfd_mips_elf32_swap_gptab_out): New function. (mips_elf_object_p): If last symbol is LOCAL, set elf_bad_symtab. (mips_elf_final_write_processing): Set sh_info field for .gptab.* sections. (mips_elf_fake_sections): Set sh_entsize for .gptab.* sections. (mips_elf_read_ecoff_info): Read and free external symbols last, not first, for clarity. (struct mips_elf_link_hash_entry): Define new structure. (struct mips_elf_link_hash_table): Define new structure. (mips_elf_link_hash_lookup): Define new macro. (mips_elf_link_hash_traverse): Define new macro. (mips_elf_hash_table): Define new macro. (mips_elf_link_hash_newfunc): New static function. (mips_elf_link_hash_table_create): New static function. (mips_elf_add_symbol_hook): New static function. (struct extsym_info): Define new structure. (mips_elf_get_extr, mips_elf_set_index): Remove. (mips_elf_output_extsym): New static function. (gptab_compare): New static function. (mips_elf_final_link): Rewrite to use ELF backend linker, and to merge gptab information in input files. (mips_elf_relocate_hi16): New static function. (mips_elf_relocate_section): New static function. (bfd_elf32_bfd_link_hash_table_create): Define as macro before including elf32-target.h. (elf_backend_relocate_section): Likewise. (elf_backend_add_symbol_hook): Likewise. * elf.c (_bfd_elf_link_hash_newfunc): Rename from elf_link_hash_newfunc and make globally visible. Change caller. (_bfd_elf_link_hash_table_init): New function, broken out of _bfd_elf_link_hash_table_create. (_bfd_elf_link_hash_table_create): Use _bfd_elf_link_hash_table_init. * libelf.h (struct elf_obj_tdata): Add new field bad_symtab. (elf_bad_symtab): Define new accessor macro. (_bfd_elf_link_hash_newfunc): Declare. (_bew_elf_link_hash_table_init): Declare. * elfcode.h (elf_object_p): Call backend object_p hook after swapping in all the section headers. (map_program_segments): Correct typo: Internal for External. (elf_link_add_object_symbols): If elf_bad_symtab is set, read all the symbols. Skip STB_LOCAL symbols rather than giving an error. (elf_bfd_final_link): If elf_bad_symtab is set, allocate space for all symbols, not just locals. (elf_link_output_extsym): Only skip a symbol not mentioned by a regular file if it is mentioned by a dynamic object. (elf_link_input_bfd): If elf_bad_symtab is set, read all the symbols. --- bfd/ChangeLog | 54 +++++++++++++++++++++++++++++ bfd/elf.c | 35 +++++++++++-------- bfd/elfcode.h | 95 +++++++++++++++++++++++++++++++++++++-------------- bfd/libelf.h | 15 ++++++++ 4 files changed, 160 insertions(+), 39 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index aa8eace0f7a..280b40ffed0 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,57 @@ +Tue May 24 16:17:18 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + Make MIPS ELF use new ELF backend linker. No shared library + support yet. + * elf32-mips.c (bfd_mips_elf32_swap_gptab_in): New function. + (bfd_mips_elf32_swap_gptab_out): New function. + (mips_elf_object_p): If last symbol is LOCAL, set elf_bad_symtab. + (mips_elf_final_write_processing): Set sh_info field for .gptab.* + sections. + (mips_elf_fake_sections): Set sh_entsize for .gptab.* sections. + (mips_elf_read_ecoff_info): Read and free external symbols last, + not first, for clarity. + (struct mips_elf_link_hash_entry): Define new structure. + (struct mips_elf_link_hash_table): Define new structure. + (mips_elf_link_hash_lookup): Define new macro. + (mips_elf_link_hash_traverse): Define new macro. + (mips_elf_hash_table): Define new macro. + (mips_elf_link_hash_newfunc): New static function. + (mips_elf_link_hash_table_create): New static function. + (mips_elf_add_symbol_hook): New static function. + (struct extsym_info): Define new structure. + (mips_elf_get_extr, mips_elf_set_index): Remove. + (mips_elf_output_extsym): New static function. + (gptab_compare): New static function. + (mips_elf_final_link): Rewrite to use ELF backend linker, and to + merge gptab information in input files. + (mips_elf_relocate_hi16): New static function. + (mips_elf_relocate_section): New static function. + (bfd_elf32_bfd_link_hash_table_create): Define as macro before + including elf32-target.h. + (elf_backend_relocate_section): Likewise. + (elf_backend_add_symbol_hook): Likewise. + * elf.c (_bfd_elf_link_hash_newfunc): Rename from + elf_link_hash_newfunc and make globally visible. Change caller. + (_bfd_elf_link_hash_table_init): New function, broken out of + _bfd_elf_link_hash_table_create. + (_bfd_elf_link_hash_table_create): Use + _bfd_elf_link_hash_table_init. + * libelf.h (struct elf_obj_tdata): Add new field bad_symtab. + (elf_bad_symtab): Define new accessor macro. + (_bfd_elf_link_hash_newfunc): Declare. + (_bew_elf_link_hash_table_init): Declare. + * elfcode.h (elf_object_p): Call backend object_p hook after + swapping in all the section headers. + (map_program_segments): Correct typo: Internal for External. + (elf_link_add_object_symbols): If elf_bad_symtab is set, read all + the symbols. Skip STB_LOCAL symbols rather than giving an error. + (elf_bfd_final_link): If elf_bad_symtab is set, allocate space for + all symbols, not just locals. + (elf_link_output_extsym): Only skip a symbol not mentioned by a + regular file if it is mentioned by a dynamic object. + (elf_link_input_bfd): If elf_bad_symtab is set, read all the + symbols. + Fri May 20 13:38:23 1994 Jeff Law (law@snake.cs.utah.edu) * som.c (som_set_reloc_info): Do not set any relocation info diff --git a/bfd/elf.c b/bfd/elf.c index b5c23db365d..3e1e712f84f 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -301,15 +301,10 @@ bfd_elf_generic_reloc (abfd, return bfd_reloc_continue; } -/* Generic ELF link code. */ - -static struct bfd_hash_entry *elf_link_hash_newfunc - PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); - /* Create an entry in an ELF linker hash table. */ -static struct bfd_hash_entry * -elf_link_hash_newfunc (entry, table, string) +struct bfd_hash_entry * +_bfd_elf_link_hash_newfunc (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string; @@ -347,6 +342,23 @@ elf_link_hash_newfunc (entry, table, string) return (struct bfd_hash_entry *) ret; } +/* Initialize an ELF linker hash table. */ + +boolean +_bfd_elf_link_hash_table_init (table, abfd, newfunc) + struct elf_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->dynobj = NULL; + table->dynsymcount = 0; + table->dynstr = NULL; + table->bucketcount = 0; + return _bfd_link_hash_table_init (&table->root, abfd, newfunc); +} + /* Create an ELF linker hash table. */ struct bfd_link_hash_table * @@ -362,17 +374,12 @@ _bfd_elf_link_hash_table_create (abfd) bfd_set_error (bfd_error_no_memory); return NULL; } - if (! _bfd_link_hash_table_init (&ret->root, abfd, - elf_link_hash_newfunc)) + + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc)) { bfd_release (abfd, ret); return NULL; } - ret->dynobj = NULL; - ret->dynsymcount = 0; - ret->dynstr = NULL; - ret->bucketcount = 0; - return &ret->root; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index db0316aac18..21deffdf167 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -939,14 +939,6 @@ elf_object_p (abfd) /* Remember the entry point specified in the ELF file header. */ bfd_get_start_address (abfd) = i_ehdrp->e_entry; - /* Let the backend double check the format and override global - information. */ - if (ebd->elf_backend_object_p) - { - if ((*ebd->elf_backend_object_p) (abfd) == false) - goto got_wrong_format_error; - } - /* Allocate space for a copy of the section header table in internal form, seek to the section header table in the file, read it in, and convert it to internal form. */ @@ -997,6 +989,14 @@ elf_object_p (abfd) goto got_no_match; } + /* Let the backend double check the format and override global + information. */ + if (ebd->elf_backend_object_p) + { + if ((*ebd->elf_backend_object_p) (abfd) == false) + goto got_wrong_format_error; + } + return (abfd->xvec); got_wrong_format_error: @@ -1914,7 +1914,7 @@ map_program_segments (abfd, off, first, phdr_size) /* Make sure the return value from get_program_header_size matches what we computed here. */ - if (phdr_count != phdr_size / sizeof (Elf_Internal_Phdr)) + if (phdr_count != phdr_size / sizeof (Elf_External_Phdr)) abort (); /* Set up program header information. */ @@ -4111,6 +4111,7 @@ elf_link_add_object_symbols (abfd, info) Elf_Internal_Shdr *hdr; size_t symcount; size_t extsymcount; + size_t extsymoff; Elf_External_Sym *buf = NULL; struct elf_link_hash_entry **sym_hash; boolean dynamic; @@ -4128,7 +4129,16 @@ elf_link_add_object_symbols (abfd, info) /* The sh_info field of the symtab header tells us where the external symbols start. We don't care about the local symbols at this point. */ - extsymcount = symcount - hdr->sh_info; + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } buf = (Elf_External_Sym *) malloc (extsymcount * sizeof (Elf_External_Sym)); if (buf == NULL && extsymcount != 0) @@ -4251,7 +4261,7 @@ elf_link_add_object_symbols (abfd, info) } if (bfd_seek (abfd, - hdr->sh_offset + hdr->sh_info * sizeof (Elf_External_Sym), + hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym), SEEK_SET) != 0 || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd) != extsymcount * sizeof (Elf_External_Sym))) @@ -4283,9 +4293,9 @@ elf_link_add_object_symbols (abfd, info) { /* This should be impossible, since ELF requires that all global symbols follow all local symbols, and that sh_info - point to the first global symbol. */ - bfd_set_error (bfd_error_bad_value); - goto error_return; + point to the first global symbol. Unfortunatealy, Irix 5 + screws this up. */ + continue; } else if (bind == STB_GLOBAL) flags = BSF_GLOBAL; @@ -5093,10 +5103,19 @@ elf_bfd_final_link (abfd, info) /* We are interested in just local symbols, not all symbols. */ - if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour - && (elf_tdata (sec->owner)->symtab_hdr.sh_info - > max_sym_count)) - max_sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; + if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour) + { + size_t sym_count; + + if (elf_bad_symtab (sec->owner)) + sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size + / sizeof (Elf_External_Sym)); + else + sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; + + if (sym_count > max_sym_count) + max_sym_count = sym_count; + } if ((sec->flags & SEC_RELOC) != 0) { @@ -5688,7 +5707,9 @@ elf_link_output_extsym (h, data) output it. */ if (h->indx == -2) strip = false; - else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) strip = true; else if (finfo->info->strip == strip_all @@ -5843,6 +5864,8 @@ elf_link_input_bfd (finfo, input_bfd) asection **)); bfd *output_bfd; Elf_Internal_Shdr *symtab_hdr; + size_t locsymcount; + size_t extsymoff; Elf_External_Sym *esym; Elf_External_Sym *esymend; Elf_Internal_Sym *isym; @@ -5860,18 +5883,29 @@ elf_link_input_bfd (finfo, input_bfd) if (elf_elfheader (input_bfd)->e_type == ET_DYN) return true; - /* Read the local symbols. */ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + extsymoff = 0; + } + else + { + locsymcount = symtab_hdr->sh_info; + extsymoff = symtab_hdr->sh_info; + } + + /* Read the local symbols. */ if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym), - symtab_hdr->sh_info, input_bfd) - != symtab_hdr->sh_info * sizeof (Elf_External_Sym))) + locsymcount, input_bfd) + != locsymcount * sizeof (Elf_External_Sym))) return false; /* Swap in the local symbols and write out the ones which we know are going into the output file. */ esym = finfo->external_syms; - esymend = esym + symtab_hdr->sh_info; + esymend = esym + locsymcount; isym = finfo->internal_syms; pindex = finfo->indices; ppsection = finfo->sections; @@ -5884,6 +5918,15 @@ elf_link_input_bfd (finfo, input_bfd) elf_swap_symbol_in (input_bfd, esym, isym); *pindex = -1; + if (elf_bad_symtab (input_bfd)) + { + if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) + { + *ppsection = NULL; + continue; + } + } + if (isym->st_shndx == SHN_UNDEF) isec = &bfd_und_section; else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE) @@ -6084,7 +6127,9 @@ elf_link_input_bfd (finfo, input_bfd) if (r_symndx == 0) continue; - if (r_symndx >= symtab_hdr->sh_info) + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) { long indx; @@ -6095,7 +6140,7 @@ elf_link_input_bfd (finfo, input_bfd) reloc to point to the global hash table entry for this symbol. The symbol index is then set at the end of elf_bfd_final_link. */ - indx = r_symndx - symtab_hdr->sh_info; + indx = r_symndx - extsymoff; *rel_hash = elf_sym_hashes (input_bfd)[indx]; /* Setting the index to -2 tells diff --git a/bfd/libelf.h b/bfd/libelf.h index 25d56b05cb8..6850abaf5f2 100644 --- a/bfd/libelf.h +++ b/bfd/libelf.h @@ -416,6 +416,13 @@ struct elf_obj_tdata table, used when linking. This is indexed by the symbol index minus the sh_info field of the symbol table header. */ struct elf_link_hash_entry **sym_hashes; + + /* Irix 5 often screws up the symbol table, sorting local symbols + after global symbols. This flag is set if the symbol table in + this BFD appears to be screwed up. If it is, we ignore the + sh_info field in the symbol table header, and always read all the + symbols. */ + boolean bad_symtab; }; #define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) @@ -434,6 +441,7 @@ struct elf_obj_tdata #define elf_gp(bfd) (elf_tdata(bfd) -> gp) #define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) #define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) +#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) extern char * elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned)); extern char * elf_get_str_section PARAMS ((bfd *, unsigned)); @@ -455,8 +463,15 @@ extern boolean bfd_elf_mkobject PARAMS ((bfd *)); extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *)); extern boolean _bfd_elf_make_section_from_shdr PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, const char *name)); +extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create PARAMS ((bfd *)); +extern boolean _bfd_elf_link_hash_table_init + PARAMS ((struct elf_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); extern boolean bfd_elf32_write_object_contents PARAMS ((bfd *)); extern boolean bfd_elf64_write_object_contents PARAMS ((bfd *)); -- 2.30.2