+ asection *sec = text_section_order[i];
+ asection *exidx_sec;
+ struct _tic6x_elf_section_data *tic6x_data
+ = get_tic6x_elf_section_data (sec);
+ struct _tic6x_elf_section_data *exidx_data;
+ bfd_byte *contents = NULL;
+ int deleted_exidx_bytes = 0;
+ bfd_vma j;
+ tic6x_unwind_table_edit *unwind_edit_head = NULL;
+ tic6x_unwind_table_edit *unwind_edit_tail = NULL;
+ Elf_Internal_Shdr *hdr;
+ bfd *ibfd;
+
+ if (tic6x_data == NULL)
+ continue;
+
+ exidx_sec = tic6x_data->u.text.tic6x_exidx_sec;
+ if (exidx_sec == NULL)
+ {
+ /* Section has no unwind data. */
+ if (last_unwind_type == 0 || !last_exidx_sec)
+ continue;
+
+ /* Ignore zero sized sections. */
+ if (sec->size == 0)
+ continue;
+
+ elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec);
+ last_unwind_type = 0;
+ continue;
+ }
+
+ /* Skip /DISCARD/ sections. */
+ if (bfd_is_abs_section (exidx_sec->output_section))
+ continue;
+
+ hdr = &elf_section_data (exidx_sec)->this_hdr;
+ if (hdr->sh_type != SHT_C6000_UNWIND)
+ continue;
+
+ exidx_data = get_tic6x_elf_section_data (exidx_sec);
+ if (exidx_data == NULL)
+ continue;
+
+ ibfd = exidx_sec->owner;
+
+ if (hdr->contents != NULL)
+ contents = hdr->contents;
+ else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents))
+ /* An error? */
+ continue;
+
+ for (j = 0; j < hdr->sh_size; j += 8)
+ {
+ unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4);
+ int unwind_type;
+ int elide = 0;
+
+ /* An EXIDX_CANTUNWIND entry. */
+ if (second_word == 1)
+ {
+ if (last_unwind_type == 0)
+ elide = 1;
+ unwind_type = 0;
+ }
+ /* Inlined unwinding data. Merge if equal to previous. */
+ else if ((second_word & 0x80000000) != 0)
+ {
+ if (merge_exidx_entries
+ && last_second_word == second_word
+ && last_unwind_type == 1)
+ elide = 1;
+ unwind_type = 1;
+ last_second_word = second_word;
+ }
+ /* Normal table entry. In theory we could merge these too,
+ but duplicate entries are likely to be much less common. */
+ else
+ unwind_type = 2;
+
+ if (elide)
+ {
+ elf32_tic6x_add_unwind_table_edit (&unwind_edit_head,
+ &unwind_edit_tail, DELETE_EXIDX_ENTRY, NULL, j / 8);
+
+ deleted_exidx_bytes += 8;
+ }
+
+ last_unwind_type = unwind_type;
+ }
+
+ /* Free contents if we allocated it ourselves. */
+ if (contents != hdr->contents)
+ free (contents);
+
+ /* Record edits to be applied later (in elf32_tic6x_write_section). */
+ exidx_data->u.exidx.unwind_edit_list = unwind_edit_head;
+ exidx_data->u.exidx.unwind_edit_tail = unwind_edit_tail;
+
+ if (deleted_exidx_bytes > 0)
+ elf32_tic6x_adjust_exidx_size (exidx_sec, -deleted_exidx_bytes);
+
+ last_exidx_sec = exidx_sec;
+ last_text_sec = sec;
+ }
+
+ /* Add terminating CANTUNWIND entry. */
+ if (last_exidx_sec && last_unwind_type != 0)
+ elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec);
+
+ return TRUE;
+}
+
+/* Add ADDEND to lower 31 bits of VAL, leaving other bits unmodified. */
+
+static unsigned long
+elf32_tic6x_add_low31 (unsigned long val, bfd_vma addend)
+{
+ return (val & ~0x7ffffffful) | ((val + addend) & 0x7ffffffful);
+}
+
+/* Copy an .c6xabi.exidx table entry, adding OFFSET to (applied) PREL31
+ relocations. OFFSET is in bytes, and will be scaled before encoding. */
+
+
+static void
+elf32_tic6x_copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from,
+ bfd_vma offset)
+{
+ unsigned long first_word = bfd_get_32 (output_bfd, from);
+ unsigned long second_word = bfd_get_32 (output_bfd, from + 4);
+
+ offset >>= 1;
+ /* High bit of first word is supposed to be zero. */
+ if ((first_word & 0x80000000ul) == 0)
+ first_word = elf32_tic6x_add_low31 (first_word, offset);
+
+ /* If the high bit of the first word is clear, and the bit pattern is not 0x1
+ (EXIDX_CANTUNWIND), this is an offset to an .c6xabi.extab entry. */
+ if ((second_word != 0x1) && ((second_word & 0x80000000ul) == 0))
+ second_word = elf32_tic6x_add_low31 (second_word, offset);
+
+ bfd_put_32 (output_bfd, first_word, to);
+ bfd_put_32 (output_bfd, second_word, to + 4);
+}
+
+/* Do the actual mangling of exception index tables. */
+
+static bfd_boolean
+elf32_tic6x_write_section (bfd *output_bfd,
+ struct bfd_link_info *link_info,
+ asection *sec,
+ bfd_byte *contents)
+{
+ _tic6x_elf_section_data *tic6x_data;
+ struct elf32_tic6x_link_hash_table *globals
+ = elf32_tic6x_hash_table (link_info);
+ bfd_vma offset = sec->output_section->vma + sec->output_offset;
+
+ if (globals == NULL)
+ return FALSE;
+
+ /* If this section has not been allocated an _tic6x_elf_section_data
+ structure then we cannot record anything. */
+ tic6x_data = get_tic6x_elf_section_data (sec);
+ if (tic6x_data == NULL)
+ return FALSE;
+
+ if (tic6x_data->elf.this_hdr.sh_type != SHT_C6000_UNWIND)
+ return FALSE;