diff options
author | Alan Modra <amodra@gmail.com> | 2019-11-27 10:51:27 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-11-27 11:58:17 +1030 |
commit | 96e2dbda089775359b130e16a337c169d67abc6b (patch) | |
tree | bf6bd5d7b9411b4a1e58d7f232ec0ebc866348c0 | |
parent | 855bae2c96421af06af9c77ed9b94b3dea5ae016 (diff) | |
download | gdb-96e2dbda089775359b130e16a337c169d67abc6b.zip gdb-96e2dbda089775359b130e16a337c169d67abc6b.tar.gz gdb-96e2dbda089775359b130e16a337c169d67abc6b.tar.bz2 |
Correct R_SH_IND12W handling
Using bfd_vma for insn is to avoid having to worry about sign
propagation in expressions involving insn and sym_value when bfd_vma
is not the same as unsigned long.
* elf32-sh.c (sh_reloc): Use a bfd_vma insn.
(sh_reloc <R_SH_IND12W>): Divide calculated relocation value
by two before applying to insn. Correct overflow test.
* coff-sh.c (sh_reloc): Likewise.
-rw-r--r-- | bfd/ChangeLog | 7 | ||||
-rw-r--r-- | bfd/coff-sh.c | 16 | ||||
-rw-r--r-- | bfd/elf32-sh.c | 14 |
3 files changed, 20 insertions, 17 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 515a127..3ef8515 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2019-11-27 Alan Modra <amodra@gmail.com> + + * elf32-sh.c (sh_reloc): Use a bfd_vma insn. + (sh_reloc <R_SH_IND12W>): Divide calculated relocation value + by two before applying to insn. Correct overflow test. + * coff-sh.c (sh_reloc): Likewise. + 2019-11-26 Nick Clifton <nickc@redhat.com> * elf32-sh.c (sh_elf_reloc): Use a signed_vma when checking for a diff --git a/bfd/coff-sh.c b/bfd/coff-sh.c index 1077a20..e1bfaf0 100644 --- a/bfd/coff-sh.c +++ b/bfd/coff-sh.c @@ -567,7 +567,7 @@ sh_reloc (bfd * abfd, bfd * output_bfd, char ** error_message ATTRIBUTE_UNUSED) { - unsigned long insn; + bfd_vma insn; bfd_vma sym_value; unsigned short r_type; bfd_vma addr = reloc_entry->address; @@ -610,14 +610,14 @@ sh_reloc (bfd * abfd, #endif insn = bfd_get_32 (abfd, hit_data); insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); + bfd_put_32 (abfd, insn, hit_data); break; #ifdef COFF_WITH_PE case R_SH_IMAGEBASE: insn = bfd_get_32 (abfd, hit_data); insn += sym_value + reloc_entry->addend; insn -= pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); + bfd_put_32 (abfd, insn, hit_data); break; #endif case R_SH_PCDISP: @@ -627,12 +627,10 @@ sh_reloc (bfd * abfd, + input_section->output_offset + addr + 4); - sym_value += (insn & 0xfff) << 1; - if (insn & 0x800) - sym_value -= 0x1000; - insn = (insn & 0xf000) | (sym_value & 0xfff); - bfd_put_16 (abfd, (bfd_vma) insn, hit_data); - if ((bfd_signed_vma) sym_value < -0x1000 || sym_value >= 0x1000) + sym_value += (((insn & 0xfff) ^ 0x800) - 0x800) << 1; + insn = (insn & 0xf000) | ((sym_value >> 1) & 0xfff); + bfd_put_16 (abfd, insn, hit_data); + if (sym_value + 0x1000 >= 0x2000 || (sym_value & 1) != 0) return bfd_reloc_overflow; break; default: diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c index 863e2e1..be4256c 100644 --- a/bfd/elf32-sh.c +++ b/bfd/elf32-sh.c @@ -232,7 +232,7 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in, void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { - unsigned long insn; + bfd_vma insn; bfd_vma sym_value; enum elf_sh_reloc_type r_type; bfd_vma addr = reloc_entry->address; @@ -274,7 +274,7 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in, case R_SH_DIR32: insn = bfd_get_32 (abfd, hit_data); insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); + bfd_put_32 (abfd, insn, hit_data); break; case R_SH_IND12W: insn = bfd_get_16 (abfd, hit_data); @@ -283,12 +283,10 @@ sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in, + input_section->output_offset + addr + 4); - sym_value += (insn & 0xfff) << 1; - if (insn & 0x800) - sym_value -= 0x1000; - insn = (insn & 0xf000) | (sym_value & 0xfff); - bfd_put_16 (abfd, (bfd_vma) insn, hit_data); - if ((bfd_signed_vma) sym_value < -0x1000 || sym_value >= 0x1000) + sym_value += (((insn & 0xfff) ^ 0x800) - 0x800) << 1; + insn = (insn & 0xf000) | ((sym_value >> 1) & 0xfff); + bfd_put_16 (abfd, insn, hit_data); + if (sym_value + 0x1000 >= 0x2000 || (sym_value & 1) != 0) return bfd_reloc_overflow; break; default: |