[Patch, avr] Fix PR 12494 - Make relaxation consider relocations from all sections before deleting ret

Senthil Kumar Selvaraj senthil_kumar.selvaraj@atmel.com
Thu Mar 21 13:28:00 GMT 2013

This patch fixes PR 12494 (relaxation leads to wrong code optimization),
by considering relocations from all sections in the BFD before
determining that it is safe to delete a ret instruction.

The linker relaxation code, as part of relaxing call/ret sequences to
jumps, checks whether the ret instruction involved is referred by
symbols or by relocation values, before deleting the instruction. The
current code only checks relocations in the same (input) section
containing the ret instruction.

This breaks if a relocation entry is emitted in a different section -
which is what happened in the buggy scenario. Computed gotos caused the
compiler to place the array of labels in a different section (.rodata),
and the assembler dutifully emitted relocations in that section (values
resolve to the actual label locations in the .text section). The linker, 
however, only considered relocations in the .text section and deleted the
ret instruction.

The fix simply iterates over relocations in all input sections in the BFD,
instead of just the input section containing the instruction to delete.

If ok, could someone apply please?


2013-03-21	Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>

	* elf32-avr.c (elf32_avr_relax_section) : Loop over all input

diff --git bfd/elf32-avr.c bfd/elf32-avr.c
index a2d4401..a5a9395 100644
--- bfd/elf32-avr.c
+++ bfd/elf32-avr.c
@@ -2189,15 +2189,20 @@ elf32_avr_relax_section (bfd *abfd,
 			/* Now we check for relocations pointing to ret.  */
+			struct bfd_section *isec;
+			for (isec = abfd->sections; isec && deleting_ret_is_safe; isec = isec->next)
 			  Elf_Internal_Rela *rel;
 			  Elf_Internal_Rela *relend;
+			  rel = elf_section_data (isec)->relocs;
+			  if (rel == NULL)
+			    rel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
-			  relend = elf_section_data (sec)->relocs
-			    + sec->reloc_count;
+			  relend = rel + isec->reloc_count;
-			  for (rel = elf_section_data (sec)->relocs;
-			       rel < relend; rel++)
+			  for (; rel && rel < relend; rel++)
 			      bfd_vma reloc_target = 0;
@@ -2259,6 +2264,7 @@ elf32_avr_relax_section (bfd *abfd,
 					    " 0x%x could not be deleted. ret"
 					    " is target of a relocation.\n",
 					    (int) address_of_ret);
+					break;

More information about the Binutils mailing list