aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephane Carrez <stcarrez@nerim.fr>2002-10-12 14:00:55 +0000
committerStephane Carrez <stcarrez@nerim.fr>2002-10-12 14:00:55 +0000
commit9b691193ef8f68fa38ef60205bccdeedec1fadea (patch)
tree2f0388f185df6a9e7959638cda924daa788b7ff9
parent1f4c5b4746c8befd34e2734ab950dfdbef9b9e21 (diff)
downloadgdb-9b691193ef8f68fa38ef60205bccdeedec1fadea.zip
gdb-9b691193ef8f68fa38ef60205bccdeedec1fadea.tar.gz
gdb-9b691193ef8f68fa38ef60205bccdeedec1fadea.tar.bz2
* 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.
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-m68hc11.c45
2 files changed, 45 insertions, 6 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index ce67be8..ba16bd9 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,11 @@
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.
+
+2002-10-12 Stephane Carrez <stcarrez@nerim.fr>
+
* elf32-m68hc11.c (m68hc11_elf_relax_section): Update symbols
handling to use Elf_Internal_Sym.
(m68hc11_elf_relax_delete_bytes): Likewise.
diff --git a/bfd/elf32-m68hc11.c b/bfd/elf32-m68hc11.c
index c448c94..ae4bb98 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;
}
}
}