This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: Fix [ Bug #1403 ] Branch adjustment to another section not correct when doing linker relaxation


Hi!

This patch fixes HC11 linker relaxation bug:

[ Bug #1403 ] Branch adjustment to another section not correct when doing linker relaxation
http://savannah.gnu.org/bugs/?func=detailbug&bug_id=1403&group_id=2424

In the following code:

.sect .text
jmp foo
jmp bar

.sect .text.foo_bar
foo: rts
bar: rts

The first jmp is relaxed and reduces the section's size by 1.
When we process the second jmp for relax the symbol value of bar is
computed using the old output section offset (it does not yet take
into account the change of size of the current section). It is necessary
to let the linker re-compute the section offsets before processing
correctly this reloc. It will be treated during a next relaxation pass.

Committed this patch to fix the bug.

Stephane

2002-10-12 Stephane Carrez <stcarrez@nerim.fr>

* elf32-m68hc11.c (m68hc11_elf_relax_section): Don't treat relocs
with symbols in other sections if we relaxed something; the sections
output offsets must be re-computed before.
Index: elf32-m68hc11.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-m68hc11.c,v
retrieving revision 1.10
diff -u -p -r1.10 elf32-m68hc11.c
--- elf32-m68hc11.c	12 Oct 2002 13:35:25 -0000	1.10
+++ elf32-m68hc11.c	12 Oct 2002 13:53:10 -0000
@@ -693,6 +693,7 @@ m68hc11_elf_relax_section (abfd, sec, li
       bfd_vma symval;
       bfd_vma value;
       Elf_Internal_Sym *isym;
+      asection *sym_sec;
 
       /* If this isn't something that can be relaxed, then ignore
 	 this reloc.  */
@@ -791,8 +792,6 @@ m68hc11_elf_relax_section (abfd, sec, li
       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
@@ -819,9 +818,11 @@ m68hc11_elf_relax_section (abfd, sec, li
 	      continue;
 	    }
 
+          isym = 0;
+          sym_sec = h->root.u.def.section;
 	  symval = (h->root.u.def.value
-		    + h->root.u.def.section->output_section->vma
-		    + h->root.u.def.section->output_offset);
+		    + sym_sec->output_section->vma
+		    + sym_sec->output_offset);
 	}
 
       if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_GROUP)
@@ -838,6 +839,32 @@ m68hc11_elf_relax_section (abfd, sec, li
           continue;
         }
 
+      /* When we relax some bytes, the size of our section changes.
+         This affects the layout of next input sections that go in our
+         output section.  When the symbol is part of another section that
+         will go in the same output section as the current one, it's
+         final address may now be incorrect (too far).  We must let the
+         linker re-compute all section offsets before processing this
+         reloc.  Code example:
+
+                                Initial             Final
+         .sect .text            section size = 6    section size = 4
+         jmp foo
+         jmp bar
+         .sect .text.foo_bar    output_offset = 6   output_offset = 4
+         foo: rts
+         bar: rts
+
+         If we process the reloc now, the jmp bar is replaced by a
+         relative branch to the initial bar address (output_offset 6).  */
+      if (*again && sym_sec != sec
+          && sym_sec->output_section == sec->output_section)
+        {
+          prev_insn_group = 0;
+          prev_insn_branch = 0;
+          continue;
+        }
+      
       value = symval;
       /* Try to turn a far branch to a near branch.  */
       if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16
@@ -883,6 +910,7 @@ m68hc11_elf_relax_section (abfd, sec, li
                                               irel->r_offset - 1, 3);
             }
           prev_insn_branch = 0;
+          *again = true;
         }
 
       /* Try to turn a 16 bit address into a 8 bit page0 address.  */
@@ -904,6 +932,8 @@ m68hc11_elf_relax_section (abfd, sec, li
 
           if (prev_insn_group)
             {
+              unsigned long old_sec_size = sec->_cooked_size;
+              
               /* Note that we've changed the reldection contents, etc.  */
               elf_section_data (sec)->relocs = internal_relocs;
               free_relocs = NULL;
@@ -921,6 +951,8 @@ m68hc11_elf_relax_section (abfd, sec, li
               prev_insn_group = 0;
               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                            R_M68HC11_NONE);
+              if (sec->_cooked_size != old_sec_size)
+                *again = true;
               continue;
             }
           
@@ -956,8 +988,7 @@ m68hc11_elf_relax_section (abfd, sec, li
           irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                        R_M68HC11_8);
 
-          /* That will change things, so, we should relax again.
-             Note that this is not required, and it may be slow.  */
+          /* That will change things, so, we should relax again.  */
           *again = true;
         }
       else if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_16)
@@ -999,6 +1030,8 @@ m68hc11_elf_relax_section (abfd, sec, li
                                                R_M68HC11_NONE);
                   m68hc11_elf_relax_delete_bytes (abfd, sec,
                                                   irel->r_offset + 1, 1);
+                  /* That will change things, so, we should relax again.  */
+                  *again = true;
                 }
             }
         }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]