From 9b691193ef8f68fa38ef60205bccdeedec1fadea Mon Sep 17 00:00:00 2001 From: Stephane Carrez Date: Sat, 12 Oct 2002 14:00:55 +0000 Subject: [PATCH] * 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. --- bfd/ChangeLog | 6 ++++++ bfd/elf32-m68hc11.c | 45 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ce67be8d6e9..ba16bd99ad4 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2002-10-12 Stephane Carrez + + * 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. + 2002-10-12 Stephane Carrez * elf32-m68hc11.c (m68hc11_elf_relax_section): Update symbols diff --git a/bfd/elf32-m68hc11.c b/bfd/elf32-m68hc11.c index c448c940c30..ae4bb982bc8 100644 --- a/bfd/elf32-m68hc11.c +++ b/bfd/elf32-m68hc11.c @@ -693,6 +693,7 @@ m68hc11_elf_relax_section (abfd, sec, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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, link_info, again) 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; } } } -- 2.30.2