+ struct avr_relax_info *relax_info;
+ struct avr_property_record *prop_record = NULL;
+ bfd_boolean did_shrink = FALSE;
+ bfd_boolean did_pad = FALSE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+ contents = elf_section_data (sec)->this_hdr.contents;
+ relax_info = get_avr_relax_info (sec);
+
+ toaddr = sec->size;
+
+ if (relax_info->records.count > 0)
+ {
+ /* There should be no property record within the range of deleted
+ bytes, however, there might be a property record for ADDR, this is
+ how we handle alignment directives.
+ Find the next (if any) property record after the deleted bytes. */
+ unsigned int i;
+
+ for (i = 0; i < relax_info->records.count; ++i)
+ {
+ bfd_vma offset = relax_info->records.items [i].offset;
+
+ BFD_ASSERT (offset <= addr || offset >= (addr + count));
+ if (offset >= (addr + count))
+ {
+ prop_record = &relax_info->records.items [i];
+ toaddr = offset;
+ break;
+ }
+ }
+ }
+
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+
+ /* Actually delete the bytes. */
+ if (toaddr - addr - count > 0)
+ {
+ memmove (contents + addr, contents + addr + count,
+ (size_t) (toaddr - addr - count));
+ did_shrink = TRUE;
+ }
+ if (prop_record == NULL)
+ {
+ sec->size -= count;
+ did_shrink = TRUE;
+ }
+ else
+ {
+ /* Use the property record to fill in the bytes we've opened up. */
+ int fill = 0;
+ switch (prop_record->type)
+ {
+ case RECORD_ORG_AND_FILL:
+ fill = prop_record->data.org.fill;
+ /* Fall through. */
+ case RECORD_ORG:
+ break;
+ case RECORD_ALIGN_AND_FILL:
+ fill = prop_record->data.align.fill;
+ /* Fall through. */
+ case RECORD_ALIGN:
+ prop_record->data.align.preceding_deleted += count;
+ break;
+ };
+ /* If toaddr == (addr + count), then we didn't delete anything, yet
+ we fill count bytes backwards from toaddr. This is still ok - we
+ end up overwriting the bytes we would have deleted. We just need
+ to remember we didn't delete anything i.e. don't set did_shrink,
+ so that we don't corrupt reloc offsets or symbol values.*/
+ memset (contents + toaddr - count, fill, count);
+ did_pad = TRUE;
+ }
+
+ if (!did_shrink)
+ return TRUE;
+
+ /* Adjust all the reloc addresses. */
+ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ {
+ bfd_vma old_reloc_address;
+
+ old_reloc_address = (sec->output_section->vma
+ + sec->output_offset + irel->r_offset);
+
+ /* Get the new reloc address. */
+ if ((irel->r_offset > addr
+ && irel->r_offset < toaddr))
+ {
+ if (debug_relax)
+ printf ("Relocation at address 0x%x needs to be moved.\n"
+ "Old section offset: 0x%x, New section offset: 0x%x \n",
+ (unsigned int) old_reloc_address,
+ (unsigned int) irel->r_offset,
+ (unsigned int) ((irel->r_offset) - count));
+
+ irel->r_offset -= count;
+ }
+
+ }
+
+ /* The reloc's own addresses are now ok. However, we need to readjust
+ the reloc's addend, i.e. the reloc's value if two conditions are met:
+ 1.) the reloc is relative to a symbol in this section that
+ is located in front of the shrinked instruction
+ 2.) symbol plus addend end up behind the shrinked instruction.
+
+ The most common case where this happens are relocs relative to
+ the section-start symbol.
+
+ This step needs to be done for all of the sections of the bfd. */
+
+ {
+ struct bfd_section *isec;
+
+ for (isec = abfd->sections; isec; isec = isec->next)
+ {
+ bfd_vma symval;
+ bfd_vma shrinked_insn_address;
+
+ if (isec->reloc_count == 0)
+ continue;
+
+ shrinked_insn_address = (sec->output_section->vma
+ + sec->output_offset + addr);
+ if (delete_shrinks_insn)
+ shrinked_insn_address -= count;
+
+ irel = elf_section_data (isec)->relocs;
+ /* PR 12161: Read in the relocs for this section if necessary. */
+ if (irel == NULL)
+ irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
+
+ for (irelend = irel + isec->reloc_count;
+ irel < irelend;
+ irel++)
+ {
+ /* Read this BFD's local symbols if we haven't done
+ so already. */
+ if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ return FALSE;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ asection *sym_sec;
+
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ symval = isym->st_value;
+ /* If the reloc is absolute, it will not have
+ a symbol or section associated with it. */
+ if (sym_sec == sec)
+ {
+ /* If there is an alignment boundary, we only need to
+ adjust addends that end up below the boundary. */
+ bfd_vma shrink_boundary = (toaddr
+ + sec->output_section->vma
+ + sec->output_offset);
+
+ symval += sym_sec->output_section->vma
+ + sym_sec->output_offset;
+
+ if (debug_relax)
+ printf ("Checking if the relocation's "
+ "addend needs corrections.\n"
+ "Address of anchor symbol: 0x%x \n"
+ "Address of relocation target: 0x%x \n"
+ "Address of relaxed insn: 0x%x \n",
+ (unsigned int) symval,
+ (unsigned int) (symval + irel->r_addend),
+ (unsigned int) shrinked_insn_address);
+
+ elf32_avr_adjust_reloc_if_spans_insn (abfd, isec, irel,
+ symval,
+ shrinked_insn_address,
+ shrink_boundary,
+ count);
+ }
+ /* else...Reference symbol is absolute. No adjustment needed. */
+ }
+ /* else...Reference symbol is extern. No need for adjusting
+ the addend. */
+ }
+ }
+ }
+
+ /* Adjust the local symbols defined in this section. */
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ /* Fix PR 9841, there may be no local symbols. */
+ if (isym != NULL)
+ {
+ Elf_Internal_Sym *isymend;
+
+ isymend = isym + symtab_hdr->sh_info;
+ for (; isym < isymend; isym++)
+ {
+ if (isym->st_shndx == sec_shndx)
+ {
+ symvalue symval = isym->st_value;
+ symvalue symend = symval + isym->st_size;
+ if (avr_should_reduce_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ {
+ /* If this assert fires then we have a symbol that ends
+ part way through an instruction. Does that make
+ sense? */
+ BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
+ isym->st_size -= count;
+ }
+ else if (avr_should_increase_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ isym->st_size += count;
+
+ if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+ isym->st_value -= count;
+ }
+ }
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ symvalue symval = sym_hash->root.u.def.value;
+ symvalue symend = symval + sym_hash->size;
+
+ if (avr_should_reduce_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ {
+ /* If this assert fires then we have a symbol that ends
+ part way through an instruction. Does that make
+ sense? */
+ BFD_ASSERT (symend >= addr + count);
+ sym_hash->size -= count;
+ }
+ else if (avr_should_increase_sym_size (symval, symend,
+ addr, toaddr, did_pad))
+ sym_hash->size += count;
+
+ if (avr_should_move_sym (symval, addr, toaddr, did_pad))
+ sym_hash->root.u.def.value -= count;
+ }
+ }
+
+ return TRUE;
+}
+
+static Elf_Internal_Sym *
+retrieve_local_syms (bfd *input_bfd)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *isymbuf;
+ size_t locsymcount;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ locsymcount = symtab_hdr->sh_info;
+
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL && locsymcount != 0)
+ isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
+ NULL, NULL, NULL);
+
+ /* Save the symbols for this input file so they won't be read again. */
+ if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents)
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ return isymbuf;
+}
+
+/* Get the input section for a given symbol index.
+ If the symbol is:
+ . a section symbol, return the section;
+ . a common symbol, return the common section;
+ . an undefined symbol, return the undefined section;
+ . an indirect symbol, follow the links;
+ . an absolute value, return the absolute section. */
+
+static asection *
+get_elf_r_symndx_section (bfd *abfd, unsigned long r_symndx)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ asection *target_sec = NULL;
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isymbuf;
+ unsigned int section_index;
+
+ isymbuf = retrieve_local_syms (abfd);
+ section_index = isymbuf[r_symndx].st_shndx;
+
+ if (section_index == SHN_UNDEF)
+ target_sec = bfd_und_section_ptr;
+ else if (section_index == SHN_ABS)
+ target_sec = bfd_abs_section_ptr;
+ else if (section_index == SHN_COMMON)
+ target_sec = bfd_com_section_ptr;
+ else
+ target_sec = bfd_section_from_elf_index (abfd, section_index);
+ }
+ else
+ {
+ unsigned long indx = r_symndx - symtab_hdr->sh_info;
+ struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx];