From ea61717495bad0a5fe182954bbb1c8a80890a98a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 17 Jul 1994 01:15:42 +0000 Subject: [PATCH] * libelf.h (struct bfd_elf_section_data): Add relocs field. (shdr_name): Remove; unused. * elfcode.h (elf_slurp_reloc_table): Rewrote to handle both REL and RELA relocs. Free up the unswapped relocs. Permit the relocs to be cached in the section_data. Correct the reloc address. (elf_slurp_reloca_table): Remove. (elf_canonicalize_reloc): Rewrote. (elf_link_input_bfd): Permit the relocs to be cached in the section data. --- bfd/ChangeLog | 12 ++ bfd/elfcode.h | 330 +++++++++++++++++--------------------------------- bfd/libelf.h | 19 ++- 3 files changed, 141 insertions(+), 220 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8146194755b..310c12d2bd0 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +Sat Jul 16 21:10:39 1994 Ian Lance Taylor (ian@sanguine.cygnus.com) + + * libelf.h (struct bfd_elf_section_data): Add relocs field. + (shdr_name): Remove; unused. + * elfcode.h (elf_slurp_reloc_table): Rewrote to handle both REL + and RELA relocs. Free up the unswapped relocs. Permit the relocs + to be cached in the section_data. Correct the reloc address. + (elf_slurp_reloca_table): Remove. + (elf_canonicalize_reloc): Rewrote. + (elf_link_input_bfd): Permit the relocs to be cached in the + section data. + Sat Jul 16 13:55:38 1994 Stan Shebs (shebs@andros.cygnus.com) * config.bfd (m88*-harris-cxux*): Recognize. diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 756d08d1cdb..223b75185cf 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -145,6 +145,8 @@ static int elf_section_from_bfd_section PARAMS ((bfd *, struct sec *)); static long elf_slurp_symbol_table PARAMS ((bfd *, asymbol **, boolean)); +static boolean elf_slurp_reloc_table PARAMS ((bfd *, asection *, asymbol **)); + static int elf_symbol_from_bfd_symbol PARAMS ((bfd *, struct symbol_cache_entry **)); @@ -2899,105 +2901,120 @@ elf_get_reloc_upper_bound (abfd, asect) return (asect->reloc_count + 1) * sizeof (arelent *); } +/* Read in and swap the external relocs. */ + static boolean -elf_slurp_reloca_table (abfd, asect, symbols) +elf_slurp_reloc_table (abfd, asect, symbols) bfd *abfd; - sec_ptr asect; + asection *asect; asymbol **symbols; { - Elf_External_Rela *native_relocs; - arelent *reloc_cache; - arelent *cache_ptr; - - unsigned int idx; + struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + struct bfd_elf_section_data * const d = elf_section_data (asect); + PTR allocated = NULL; + bfd_byte *native_relocs; + arelent *relents; + arelent *relent; + unsigned int i; + int entsize; - if (asect->relocation) - return true; - if (asect->reloc_count == 0) - return true; - if (asect->flags & SEC_CONSTRUCTOR) + if (asect->relocation != NULL) return true; - if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) - return false; - native_relocs = (Elf_External_Rela *) - bfd_alloc (abfd, asect->reloc_count * sizeof (Elf_External_Rela)); - if (!native_relocs) + BFD_ASSERT (asect->rel_filepos == d->rel_hdr.sh_offset + && (asect->reloc_count + == d->rel_hdr.sh_size / d->rel_hdr.sh_entsize)); + + native_relocs = (bfd_byte *) elf_section_data (asect)->relocs; + if (native_relocs == NULL) { - bfd_set_error (bfd_error_no_memory); - return false; - } - if (bfd_read ((PTR) native_relocs, - sizeof (Elf_External_Rela), asect->reloc_count, abfd) - != sizeof (Elf_External_Rela) * asect->reloc_count) - return false; + allocated = (PTR) malloc (d->rel_hdr.sh_size); + if (allocated == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + + if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0 + || (bfd_read (allocated, 1, d->rel_hdr.sh_size, abfd) + != d->rel_hdr.sh_size)) + goto error_return; - reloc_cache = (arelent *) - bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent))); + native_relocs = (bfd_byte *) allocated; + } - if (!reloc_cache) + relents = ((arelent *) + bfd_alloc (abfd, asect->reloc_count * sizeof (arelent))); + if (relents == NULL) { bfd_set_error (bfd_error_no_memory); - return false; + goto error_return; } - for (idx = 0; idx < asect->reloc_count; idx++) - { - Elf_Internal_Rela dst; - Elf_External_Rela *src; + entsize = d->rel_hdr.sh_entsize; + BFD_ASSERT (entsize == sizeof (Elf_External_Rel) + || entsize == sizeof (Elf_External_Rela)); - cache_ptr = reloc_cache + idx; - src = native_relocs + idx; - elf_swap_reloca_in (abfd, src, &dst); + for (i = 0, relent = relents; + i < asect->reloc_count; + i++, relent++, native_relocs += entsize) + { + Elf_Internal_Rela rela; + Elf_Internal_Rel rel; -#ifdef RELOC_PROCESSING - RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect); -#else - if (asect->flags & SEC_RELOC) - { - /* relocatable, so the offset is off of the section */ - cache_ptr->address = dst.r_offset + asect->vma; - } + if (entsize == sizeof (Elf_External_Rela)) + elf_swap_reloca_in (abfd, (Elf_External_Rela *) native_relocs, &rela); else { - /* non-relocatable, so the offset a virtual address */ - cache_ptr->address = dst.r_offset; + elf_swap_reloc_in (abfd, (Elf_External_Rel *) native_relocs, &rel); + rela.r_offset = rel.r_offset; + rela.r_info = rel.r_info; + rela.r_addend = 0; } - /* ELF_R_SYM(dst.r_info) is the symbol table offset. An offset - of zero points to the dummy symbol, which was not read into - the symbol table SYMBOLS. */ - if (ELF_R_SYM (dst.r_info) == 0) - cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + relent->address = rela.r_offset; + else + relent->address = rela.r_offset - asect->vma; + + if (ELF_R_SYM (rela.r_info) == 0) + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; else { - asymbol *s; + asymbol **ps, *s; - cache_ptr->sym_ptr_ptr = symbols + ELF_R_SYM (dst.r_info) - 1; + ps = symbols + ELF_R_SYM (rela.r_info) - 1; + s = *ps; - /* Translate any ELF section symbol into a BFD section - symbol. */ - s = *(cache_ptr->sym_ptr_ptr); - if (s->flags & BSF_SECTION_SYM) - { - cache_ptr->sym_ptr_ptr = s->section->symbol_ptr_ptr; - s = *cache_ptr->sym_ptr_ptr; - if (s->name == 0 || s->name[0] == 0) - abort (); - } + /* Canonicalize ELF section symbols. FIXME: Why? */ + if ((s->flags & BSF_SECTION_SYM) == 0) + relent->sym_ptr_ptr = ps; + else + relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; } - cache_ptr->addend = dst.r_addend; - /* Fill in the cache_ptr->howto field from dst.r_type */ - { - struct elf_backend_data *ebd = get_elf_backend_data (abfd); - (*ebd->elf_info_to_howto) (abfd, cache_ptr, &dst); - } -#endif + relent->addend = rela.r_addend; + + if (entsize == sizeof (Elf_External_Rela)) + (*ebd->elf_info_to_howto) (abfd, relent, &rela); + else + (*ebd->elf_info_to_howto_rel) (abfd, relent, &rel); } - asect->relocation = reloc_cache; + asect->relocation = relents; + + if (allocated != NULL) + free (allocated); + return true; + + error_return: + if (allocated != NULL) + free (allocated); + return false; } #ifdef DEBUG @@ -3045,129 +3062,7 @@ elf_debug_file (ehdrp) } #endif -static boolean -elf_slurp_reloc_table (abfd, asect, symbols) - bfd *abfd; - sec_ptr asect; - asymbol **symbols; -{ - Elf_External_Rel *native_relocs; - arelent *reloc_cache; - arelent *cache_ptr; - Elf_Internal_Shdr *data_hdr; - bfd_vma data_off; - unsigned long data_max; - char buf[4]; /* FIXME -- might be elf64 */ - - unsigned int idx; - - if (asect->relocation) - return true; - if (asect->reloc_count == 0) - return true; - if (asect->flags & SEC_CONSTRUCTOR) - return true; - - if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) - return false; - native_relocs = (Elf_External_Rel *) - bfd_alloc (abfd, asect->reloc_count * sizeof (Elf_External_Rel)); - if (!native_relocs) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - if (bfd_read ((PTR) native_relocs, - sizeof (Elf_External_Rel), asect->reloc_count, abfd) - != sizeof (Elf_External_Rel) * asect->reloc_count) - return false; - - reloc_cache = (arelent *) - bfd_alloc (abfd, (size_t) (asect->reloc_count * sizeof (arelent))); - - if (!reloc_cache) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - - /* Get the offset of the start of the segment we are relocating to read in - the implicit addend. */ - data_hdr = &elf_section_data (asect)->this_hdr; - data_off = data_hdr->sh_offset; - data_max = data_hdr->sh_size - sizeof (buf) + 1; - -#if DEBUG & 2 - elf_debug_section ("data section", -1, data_hdr); -#endif - - for (idx = 0; idx < asect->reloc_count; idx++) - { -#ifdef RELOC_PROCESSING - Elf_Internal_Rel dst; - Elf_External_Rel *src; - - cache_ptr = reloc_cache + idx; - src = native_relocs + idx; - elf_swap_reloc_in (abfd, src, &dst); - - RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect); -#else - Elf_Internal_Rel dst; - Elf_External_Rel *src; - - cache_ptr = reloc_cache + idx; - src = native_relocs + idx; - - elf_swap_reloc_in (abfd, src, &dst); - - if (asect->flags & SEC_RELOC) - { - /* relocatable, so the offset is off of the section */ - cache_ptr->address = dst.r_offset + asect->vma; - } - else - { - /* non-relocatable, so the offset a virtual address */ - cache_ptr->address = dst.r_offset; - } - - /* ELF_R_SYM(dst.r_info) is the symbol table offset. An offset - of zero points to the dummy symbol, which was not read into - the symbol table SYMBOLS. */ - if (ELF_R_SYM (dst.r_info) == 0) - cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - else - { - asymbol *s; - - cache_ptr->sym_ptr_ptr = symbols + ELF_R_SYM (dst.r_info) - 1; - - /* Translate any ELF section symbol into a BFD section - symbol. */ - s = *(cache_ptr->sym_ptr_ptr); - if (s->flags & BSF_SECTION_SYM) - { - cache_ptr->sym_ptr_ptr = s->section->symbol_ptr_ptr; - s = *cache_ptr->sym_ptr_ptr; - if (s->name == 0 || s->name[0] == 0) - abort (); - } - } - BFD_ASSERT (dst.r_offset <= data_max); - cache_ptr->addend = 0; - - /* Fill in the cache_ptr->howto field from dst.r_type */ - { - struct elf_backend_data *ebd = get_elf_backend_data (abfd); - (*ebd->elf_info_to_howto_rel) (abfd, cache_ptr, &dst); - } -#endif - } - - asect->relocation = reloc_cache; - return true; -} +/* Canonicalize the relocs. */ long elf_canonicalize_reloc (abfd, section, relptr, symbols) @@ -3176,28 +3071,18 @@ elf_canonicalize_reloc (abfd, section, relptr, symbols) arelent **relptr; asymbol **symbols; { - arelent *tblptr = section->relocation; - unsigned int count = 0; - int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; + arelent *tblptr; + unsigned int i; - /* snarfed from coffcode.h */ - if (use_rela_p) - { - if (! elf_slurp_reloca_table (abfd, section, symbols)) - return -1; - } - else - { - if (! elf_slurp_reloc_table (abfd, section, symbols)) - return -1; - } + if (! elf_slurp_reloc_table (abfd, section, symbols)) + return -1; tblptr = section->relocation; - - for (; count++ < section->reloc_count;) + for (i = 0; i < section->reloc_count; i++) *relptr++ = tblptr++; - *relptr = 0; + *relptr = NULL; + return section->reloc_count; } @@ -6041,12 +5926,21 @@ elf_link_input_bfd (finfo, input_bfd) if ((o->flags & SEC_RELOC) != 0) { - /* Read in the relocs. */ - input_rel_hdr = &elf_section_data (o)->rel_hdr; - if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0 - || bfd_read (finfo->external_relocs, 1, input_rel_hdr->sh_size, - input_bfd) != input_rel_hdr->sh_size) - return false; + PTR external_relocs; + + /* Get the external relocs. They may have been cached. */ + external_relocs = elf_section_data (o)->relocs; + if (external_relocs == NULL) + { + input_rel_hdr = &elf_section_data (o)->rel_hdr; + if ((bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) + != 0) + || (bfd_read (finfo->external_relocs, 1, + input_rel_hdr->sh_size, input_bfd) + != input_rel_hdr->sh_size)) + return false; + external_relocs = finfo->external_relocs; + } /* Swap in the relocs. For convenience, we always produce an Elf_Internal_Rela array; if the relocs are Rel, we set @@ -6057,7 +5951,7 @@ elf_link_input_bfd (finfo, input_bfd) Elf_External_Rel *erelend; Elf_Internal_Rela *irela; - erel = (Elf_External_Rel *) finfo->external_relocs; + erel = (Elf_External_Rel *) external_relocs; erelend = erel + o->reloc_count; irela = finfo->internal_relocs; for (; erel < erelend; erel++, irela++) @@ -6079,7 +5973,7 @@ elf_link_input_bfd (finfo, input_bfd) BFD_ASSERT (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela)); - erela = (Elf_External_Rela *) finfo->external_relocs; + erela = (Elf_External_Rela *) external_relocs; erelaend = erela + o->reloc_count; irela = finfo->internal_relocs; for (; erela < erelaend; erela++, irela++) diff --git a/bfd/libelf.h b/bfd/libelf.h index 748e4821373..84f79bb238b 100644 --- a/bfd/libelf.h +++ b/bfd/libelf.h @@ -375,14 +375,29 @@ struct elf_sym_extra typedef struct elf_sym_extra Elf_Sym_Extra; +/* Information stored for each BFD section in an ELF file. This + structure is allocated by elf_new_section_hook. */ + struct bfd_elf_section_data { + /* The ELF header for this section. */ Elf_Internal_Shdr this_hdr; + /* The ELF header for the reloc section associated with this + section, if any. */ Elf_Internal_Shdr rel_hdr; - int this_idx, rel_idx; + /* The ELF section number of this section. Only used for an output + file. */ + int this_idx; + /* The ELF section number of the reloc section associated with this + section, if any. Only used for an output file. */ + int rel_idx; + /* Used by the backend linker to store the symbol hash table entries + associated with relocs against global symbols. */ struct elf_link_hash_entry **rel_hashes; + /* A pointer to the unswapped external relocs; this may be NULL. */ + PTR relocs; }; + #define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) -#define shdr_name(abfd,shdr) (elf_shstrtab (abfd)->tab + (shdr)->sh_name) #define get_elf_backend_data(abfd) \ ((struct elf_backend_data *) (abfd)->xvec->backend_data) -- 2.30.2