summaryrefslogtreecommitdiff
path: root/bfd/elf32-m68hc11.c
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
commit78b9e3753fc29d9a24d27758a85bfde02ab8bcae (patch)
tree7c3e53d5cb2627706dfd40222d2bb7d0e659838a /bfd/elf32-m68hc11.c
parent89f9291ea0700d13d7ba766365aea9b5dec5ad1a (diff)
downloadbinutils-redhat-78b9e3753fc29d9a24d27758a85bfde02ab8bcae.tar.gz
* 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.
Diffstat (limited to 'bfd/elf32-m68hc11.c')
-rw-r--r--bfd/elf32-m68hc11.c45
1 files changed, 39 insertions, 6 deletions
diff --git a/bfd/elf32-m68hc11.c b/bfd/elf32-m68hc11.c
index c448c940c3..ae4bb982bc 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;
}
}
}