diff options
-rw-r--r-- | bfd/ChangeLog | 19 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 13 | ||||
-rw-r--r-- | bfd/elf.c | 94 | ||||
-rw-r--r-- | bfd/elf32-mips.c | 17 | ||||
-rw-r--r-- | bfd/elflink.h | 206 |
5 files changed, 248 insertions, 101 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 60a3591..e13d01e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +1999-07-01 Mark Mitchell <mark@codesourcery.com> + + * elf-bfd.h (bfd_elf_section_data): Add rel_count and rel_count2 + fields. + (_bfd_elf_init_reloc_shdr): New function. + * elf.c (_bfd_elf_new_section_hook): Use bfd_zalloc, rather than + bfd_alloc followed by memset. + (_bfd_elf_init_reloc_shdr): New function, split out from ... + (elf_fake_sections): Here. + (assign_section_numbers): Assign section numbers for the second + relocation section, if required. + * elflink.h (elf_link_output_relocs): New function. + (elf_link_size_reloc_section): Likewise. + (elf_bfd_final_link): Use elf_link_size_reloc_section. + (elf_link_input_bfd): Use elf_link_output_relocs. + + * elf32-mips.c (_bfd_mips_elf_fake_sections): Use + _bfd_elf_init_reloc_shdr to initialize rel_hdr2. + Thu Jul 1 13:58:48 1999 Jeffrey A Law (law@cygnus.com) * elf-hppa.h (_bfd_elf_hppa_gen_reloc_type): Handle R_PCREL_CALL diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 346daab..05667bd 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -574,12 +574,19 @@ struct bfd_elf_section_data /* If there is a second reloc section associated with this section, as can happen on Irix 6, this field points to the header. */ Elf_Internal_Shdr *rel_hdr2; + /* The number of relocations currently assigned to REL_HDR. */ + unsigned int rel_count; + /* The number of relocations currently assigned to REL_HDR2. */ + unsigned int rel_count2; /* 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. */ + /* The ELF section number of the reloc section indicated by + REL_HDR if any. Only used for an output file. */ int rel_idx; + /* The ELF section number of the reloc section indicated by + REL_HDR2 if any. Only used for an output file. */ + int rel_idx2; /* 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; @@ -897,6 +904,8 @@ extern boolean _bfd_elf_find_nearest_line PARAMS ((bfd *, asection *, #define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol extern int _bfd_elf_sizeof_headers PARAMS ((bfd *, boolean)); extern boolean _bfd_elf_new_section_hook PARAMS ((bfd *, asection *)); +extern boolean _bfd_elf_init_reloc_shdr + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *, boolean)); /* If the target doesn't have reloc handling written yet: */ extern void _bfd_elf_no_info_to_howto PARAMS ((bfd *, arelent *, @@ -1337,11 +1337,10 @@ _bfd_elf_new_section_hook (abfd, sec) { struct bfd_elf_section_data *sdata; - sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata)); + sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, sizeof (*sdata)); if (!sdata) return false; sec->used_by_bfd = (PTR) sdata; - memset (sdata, 0, sizeof (*sdata)); /* Indicate whether or not this section should use RELA relocations. */ sdata->use_rela_p @@ -1441,6 +1440,43 @@ bfd_section_from_phdr (abfd, hdr, index) return true; } +/* Initialize REL_HDR, the section-header for new section, containing + relocations against ASECT. If USE_RELA_P is true, we use RELA + relocations; otherwise, we use REL relocations. */ + +boolean +_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + asection *asect; + boolean use_rela_p; +{ + char *name; + struct elf_backend_data *bed; + + bed = get_elf_backend_data (abfd); + name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); + if (name == NULL) + return false; + sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); + rel_hdr->sh_name = + (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name, + true, false); + if (rel_hdr->sh_name == (unsigned int) -1) + return false; + rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; + rel_hdr->sh_entsize = (use_rela_p + ? bed->s->sizeof_rela + : bed->s->sizeof_rel); + rel_hdr->sh_addralign = bed->s->file_align; + rel_hdr->sh_flags = 0; + rel_hdr->sh_addr = 0; + rel_hdr->sh_size = 0; + rel_hdr->sh_offset = 0; + + return true; +} + /* Set up an ELF internal section header for a section. */ /*ARGSUSED*/ @@ -1580,39 +1616,15 @@ elf_fake_sections (abfd, asect, failedptrarg) (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect); /* If the section has relocs, set up a section header for the - SHT_REL[A] section. */ - if ((asect->flags & SEC_RELOC) != 0) - { - Elf_Internal_Shdr *rela_hdr; - int use_rela_p = elf_section_data (asect)->use_rela_p; - char *name; - - rela_hdr = &elf_section_data (asect)->rel_hdr; - name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); - if (name == NULL) - { - *failedptr = true; - return; - } - sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); - rela_hdr->sh_name = - (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name, - true, false); - if (rela_hdr->sh_name == (unsigned int) -1) - { - *failedptr = true; - return; - } - rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; - rela_hdr->sh_entsize = (use_rela_p - ? bed->s->sizeof_rela - : bed->s->sizeof_rel); - rela_hdr->sh_addralign = bed->s->file_align; - rela_hdr->sh_flags = 0; - rela_hdr->sh_addr = 0; - rela_hdr->sh_size = 0; - rela_hdr->sh_offset = 0; - } + SHT_REL[A] section. If two relocation sections are required for + this section, it is up to the processor-specific back-end to + create the other. */ + if ((asect->flags & SEC_RELOC) != 0 + && !_bfd_elf_init_reloc_shdr (abfd, + &elf_section_data (asect)->rel_hdr, + asect, + elf_section_data (asect)->use_rela_p)) + *failedptr = true; } /* Assign all ELF section numbers. The dummy first section is handled here @@ -1640,6 +1652,11 @@ assign_section_numbers (abfd) d->rel_idx = 0; else d->rel_idx = section_number++; + + if (d->rel_hdr2) + d->rel_idx2 = section_number++; + else + d->rel_idx2 = 0; } t->shstrtab_section = section_number++; @@ -1688,6 +1705,8 @@ assign_section_numbers (abfd) i_shdrp[d->this_idx] = &d->this_hdr; if (d->rel_idx != 0) i_shdrp[d->rel_idx] = &d->rel_hdr; + if (d->rel_idx2 != 0) + i_shdrp[d->rel_idx2] = d->rel_hdr2; /* Fill in the sh_link and sh_info fields while we're at it. */ @@ -1699,6 +1718,11 @@ assign_section_numbers (abfd) d->rel_hdr.sh_link = t->symtab_section; d->rel_hdr.sh_info = d->this_idx; } + if (d->rel_idx2 != 0) + { + d->rel_hdr2->sh_link = t->symtab_section; + d->rel_hdr2->sh_info = d->this_idx; + } switch (d->this_hdr.sh_type) { diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 9585291..50d2f23 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -2788,6 +2788,23 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec) hdr->sh_entsize = 8; } + /* The generic elf_fake_sections will set up REL_HDR using the + default kind of relocations. But, we may actually need both + kinds of relocations, so we set up the second header here. */ + if ((sec->flags & SEC_RELOC) != 0) + { + struct bfd_elf_section_data *esd; + + esd = elf_section_data (sec); + BFD_ASSERT (esd->rel_hdr2 == NULL); + esd->rel_hdr2 + = (Elf_Internal_Shdr *) bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr)); + if (!esd->rel_hdr2) + return false; + _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec, + !elf_section_data (sec)->use_rela_p); + } + return true; } diff --git a/bfd/elflink.h b/bfd/elflink.h index ca02b09..b203908 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -56,6 +56,10 @@ static boolean elf_link_read_relocs_from_section PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *)); static void elf_link_remove_section_and_adjust_dynindices PARAMS ((struct bfd_link_info *, asection *)); +static void elf_link_output_relocs + PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); +static boolean elf_link_size_reloc_section + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); /* Given an ELF BFD, add symbols to the global hash table as appropriate. */ @@ -2063,12 +2067,15 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs, return true; } -/* Read and swap the relocs for a section. They may have been cached. - If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL, - they are used as buffers to read into. They are known to be large - enough. If the INTERNAL_RELOCS relocs argument is NULL, the return - value is allocated using either malloc or bfd_alloc, according to - the KEEP_MEMORY argument. */ +/* Read and swap the relocs for a section O. They may have been + cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are + not NULL, they are used as buffers to read into. They are known to + be large enough. If the INTERNAL_RELOCS relocs argument is NULL, + the return value is allocated using either malloc or bfd_alloc, + according to the KEEP_MEMORY argument. If O has two relocation + sections (both REL and RELA relocations), then the REL_HDR + relocations will appear first in INTERNAL_RELOCS, followed by the + REL_HDR2 relocations. */ Elf_Internal_Rela * NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, @@ -3669,6 +3676,48 @@ struct elf_outext_info struct elf_final_link_info *finfo; }; +/* Compute the size of, and allocate space for, REL_HDR which is the + section header for a section containing relocations for O. */ + +static boolean +elf_link_size_reloc_section (abfd, rel_hdr, o) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + asection *o; +{ + register struct elf_link_hash_entry **p, **pend; + + /* We are overestimating the size required for the relocation + sections, in the case that we are using both REL and RELA + relocations for a single section. In that case, RELOC_COUNT will + be the total number of relocations required, and we allocate + space for that many REL relocations as well as that many RELA + relocations. This approximation is wasteful of disk space. + However, until we keep track of how many of each kind of + relocation is required, it's difficult to calculate the right + value. */ + rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count; + + /* The contents field must last into write_object_contents, so we + allocate it with bfd_alloc rather than malloc. */ + rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size); + if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) + return false; + + p = ((struct elf_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct elf_link_hash_entry *))); + if (p == NULL && o->reloc_count != 0) + return false; + + elf_section_data (o)->rel_hashes = p; + pend = p + o->reloc_count; + for (; p < pend; p++) + *p = NULL; + + return true; +} + /* Do the final step of an ELF link. */ boolean @@ -3830,32 +3879,16 @@ elf_bfd_final_link (abfd, info) { if ((o->flags & SEC_RELOC) != 0) { - Elf_Internal_Shdr *rel_hdr; - register struct elf_link_hash_entry **p, **pend; - - rel_hdr = &elf_section_data (o)->rel_hdr; - - rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count; - - /* The contents field must last into write_object_contents, - so we allocate it with bfd_alloc rather than malloc. */ - rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size); - if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) + if (!elf_link_size_reloc_section (abfd, + &elf_section_data (o)->rel_hdr, + o)) goto error_return; - p = ((struct elf_link_hash_entry **) - bfd_malloc (o->reloc_count - * sizeof (struct elf_link_hash_entry *))); - if (p == NULL && o->reloc_count != 0) + if (elf_section_data (o)->rel_hdr2 + && !elf_link_size_reloc_section (abfd, + elf_section_data (o)->rel_hdr2, + o)) goto error_return; - elf_section_data (o)->rel_hashes = p; - pend = p + o->reloc_count; - for (; p < pend; p++) - *p = NULL; - - /* Use the reloc_count field as an index when outputting the - relocs. */ - o->reloc_count = 0; } } @@ -4717,6 +4750,76 @@ elf_link_output_extsym (h, data) return true; } +/* Copy the relocations indicated by the INTERNAL_RELOCS (which + originated from the section given by INPUT_REL_HDR) to the + OUTPUT_BFD. */ + +static void +elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, + internal_relocs) + bfd *output_bfd; + asection *input_section; + Elf_Internal_Shdr *input_rel_hdr; + Elf_Internal_Rela *internal_relocs; +{ + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + Elf_Internal_Shdr *output_rel_hdr; + asection *output_section; + unsigned int *rel_countp; + + output_section = input_section->output_section; + output_rel_hdr = NULL; + + if (elf_section_data (output_section)->rel_hdr.sh_entsize + == input_rel_hdr->sh_entsize) + { + output_rel_hdr = &elf_section_data (output_section)->rel_hdr; + rel_countp = &elf_section_data (output_section)->rel_count; + } + else if (elf_section_data (output_section)->rel_hdr2 + && (elf_section_data (output_section)->rel_hdr2->sh_entsize + == input_rel_hdr->sh_entsize)) + { + output_rel_hdr = elf_section_data (output_section)->rel_hdr2; + rel_countp = &elf_section_data (output_section)->rel_count2; + } + + BFD_ASSERT (output_rel_hdr != NULL); + + irela = internal_relocs; + irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize; + if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + + erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp); + for (; irela < irelaend; irela++, erel++) + { + Elf_Internal_Rel irel; + + irel.r_offset = irela->r_offset; + irel.r_info = irela->r_info; + BFD_ASSERT (irela->r_addend == 0); + elf_swap_reloc_out (output_bfd, &irel, erel); + } + } + else + { + Elf_External_Rela *erela; + + BFD_ASSERT (input_rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp); + for (; irela < irelaend; irela++, erela++) + elf_swap_reloca_out (output_bfd, irela, erela); + } + + /* Bump the counter, so that we know where to add the next set of + relocations. */ + *rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize; +} + /* Link an input file into the linker output file. This function handles all the sections and relocations of the input file at once. This is so that we only have to read the local symbols once, and @@ -4978,7 +5081,6 @@ elf_link_input_bfd (finfo, input_bfd) Elf_Internal_Rela *irelaend; struct elf_link_hash_entry **rel_hash; Elf_Internal_Shdr *input_rel_hdr; - Elf_Internal_Shdr *output_rel_hdr; /* Adjust the reloc addresses and symbol indices. */ @@ -5109,40 +5211,16 @@ elf_link_input_bfd (finfo, input_bfd) /* Swap out the relocs. */ input_rel_hdr = &elf_section_data (o)->rel_hdr; - output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr; - BFD_ASSERT (output_rel_hdr->sh_entsize - == input_rel_hdr->sh_entsize); - irela = internal_relocs; - irelaend = irela + o->reloc_count; - if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) - { - Elf_External_Rel *erel; - - erel = ((Elf_External_Rel *) output_rel_hdr->contents - + o->output_section->reloc_count); - for (; irela < irelaend; irela++, erel++) - { - Elf_Internal_Rel irel; - - irel.r_offset = irela->r_offset; - irel.r_info = irela->r_info; - BFD_ASSERT (irela->r_addend == 0); - elf_swap_reloc_out (output_bfd, &irel, erel); - } - } - else - { - Elf_External_Rela *erela; - - BFD_ASSERT (input_rel_hdr->sh_entsize - == sizeof (Elf_External_Rela)); - erela = ((Elf_External_Rela *) output_rel_hdr->contents - + o->output_section->reloc_count); - for (; irela < irelaend; irela++, erela++) - elf_swap_reloca_out (output_bfd, irela, erela); - } - - o->output_section->reloc_count += o->reloc_count; + elf_link_output_relocs (output_bfd, o, + input_rel_hdr, + internal_relocs); + internal_relocs + += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize; + input_rel_hdr = elf_section_data (o)->rel_hdr2; + if (input_rel_hdr) + elf_link_output_relocs (output_bfd, o, + input_rel_hdr, + internal_relocs); } } |