Fix .eh_frame optimisation in linker

Andreas Schwab schwab@suse.de
Sun Aug 24 21:43:00 GMT 2008


This fixes the .eh_frame optimisation in the linker: subtracting two
unsigned int values and then adding that to a bfd_vma value results in a
wrong value when bfd_vma is wider than int and the difference is
negative.

This fixes the massive testsuite regressions in mainline GCC on ppc64,
where all exception related tests crash.  This was triggered by the
recent change to use CFI insns in the assembler output.

Tested on ppc64-linux and checked in as obvious.

Andreas.

2008-08-24  Andreas Schwab  <schwab@suse.de>

	* elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Do proper
	extension when calculating difference of offsets.

--- bfd/elf-eh-frame.c.~1.71.~	2008-08-08 21:32:05.000000000 +0200
+++ bfd/elf-eh-frame.c	2008-08-24 23:07:22.000000000 +0200
@@ -1445,7 +1445,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 
 			val = read_value (abfd, buf, per_width,
 					  get_DW_EH_PE_signed (per_encoding));
-			val += ent->offset - ent->new_offset;
+			val += (bfd_vma) ent->offset - ent->new_offset;
 			val -= extra_string + extra_data;
 			write_value (abfd, buf, val, per_width);
 			action &= ~4;
@@ -1504,7 +1504,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		  }
 		  break;
 		case DW_EH_PE_pcrel:
-		  value += ent->offset - ent->new_offset;
+		  value += (bfd_vma) ent->offset - ent->new_offset;
 		  address += (sec->output_section->vma
 			      + sec->output_offset
 			      + ent->offset + 8);
@@ -1538,7 +1538,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 	      if (value)
 		{
 		  if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel)
-		    value += ent->offset - ent->new_offset;
+		    value += (bfd_vma) ent->offset - ent->new_offset;
 		  else if (cie->u.cie.make_lsda_relative)
 		    value -= (sec->output_section->vma
 			      + sec->output_offset
@@ -1577,7 +1577,7 @@ _bfd_elf_write_section_eh_frame (bfd *ab
 		    continue;
 
 		  if ((ent->fde_encoding & 0xf0) == DW_EH_PE_pcrel)
-		    value += ent->offset + 8 - new_offset;
+		    value += (bfd_vma) ent->offset + 8 - new_offset;
 		  if (ent->make_relative)
 		    value -= (sec->output_section->vma
 			      + sec->output_offset

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."



More information about the Binutils mailing list