[binutils-gdb] alpha, rl78, rx: UB in reloc handling
Alan Modra
amodra@sourceware.org
Tue Jul 7 01:13:11 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=192a958f5725c0f5a0338ceb9de580b540db6adb
commit 192a958f5725c0f5a0338ceb9de580b540db6adb
Author: Alan Modra <amodra@gmail.com>
Date: Tue Jul 7 10:08:18 2026 +0930
alpha, rl78, rx: UB in reloc handling
This patch avoids undefined behaviour and divide by zero exceptions in
some relocation processing. In most cases, unsigned arithmetic is
used which has defined overflow characteristics. Arithmetic right
shift, division, and modulo operations have more special cases. See
the explanation in commit 30200464e9dd.
* coff-alpha.c (alpha_ecoff_get_relocated_section_contents): Avoid
UB in RSHIFT reloc.
(alpha_relocate_section): Likewise.
* elf32-rl78.c (rl78_compute_complex_reloc): Avoid UB in reloc
arithmetic.
* elf32-rx.c (rx_elf_relocate_section): Likewise.
(rx_offset_for_reloc): Likewise.
Diff:
---
bfd/coff-alpha.c | 10 +++++--
bfd/elf32-rl78.c | 36 +++++++++++++++++---------
bfd/elf32-rx.c | 79 +++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 93 insertions(+), 32 deletions(-)
diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c
index 35677e9a933..f0823cdcaa9 100644
--- a/bfd/coff-alpha.c
+++ b/bfd/coff-alpha.c
@@ -1128,7 +1128,10 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd,
break;
}
- stack[tos - 1] >>= relocation;
+ if (relocation >= 64)
+ stack[tos - 1] = 0;
+ else
+ stack[tos - 1] >>= relocation;
}
break;
@@ -1755,7 +1758,10 @@ alpha_relocate_section (bfd *output_bfd,
r = bfd_reloc_notsupported;
break;
}
- stack[tos - 1] >>= addend;
+ if (addend >= 64)
+ stack[tos - 1] = 0;
+ else
+ stack[tos - 1] >>= addend;
break;
}
}
diff --git a/bfd/elf32-rl78.c b/bfd/elf32-rl78.c
index 2b782c1463a..e9e047fcca7 100644
--- a/bfd/elf32-rl78.c
+++ b/bfd/elf32-rl78.c
@@ -442,14 +442,14 @@ rl78_compute_complex_reloc (unsigned long r_type,
case R_RL78_OPneg:
tmp1 = rl78_stack_pop (&status);
- tmp1 = - tmp1;
+ tmp1 = -(uint32_t) tmp1;
rl78_stack_push (tmp1, &status);
break;
case R_RL78_OPadd:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- tmp1 += tmp2;
+ tmp1 += (uint32_t) tmp2;
rl78_stack_push (tmp1, &status);
break;
@@ -458,41 +458,51 @@ rl78_compute_complex_reloc (unsigned long r_type,
then B, then OPSUB. So the first op we pop is B, not A. */
tmp2 = rl78_stack_pop (&status); /* B */
tmp1 = rl78_stack_pop (&status); /* A */
- tmp1 -= tmp2; /* A - B */
+ tmp1 -= (uint32_t) tmp2; /* A - B */
rl78_stack_push (tmp1, &status);
break;
case R_RL78_OPmul:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- tmp1 *= tmp2;
+ tmp1 *= (uint32_t) tmp2;
rl78_stack_push (tmp1, &status);
break;
case R_RL78_OPdiv:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- if (tmp2 != 0)
- tmp1 /= tmp2;
- else
+ if (tmp2 == 0)
{
tmp1 = 0;
status = bfd_reloc_overflow;
}
+ else if (tmp2 == 1)
+ ;
+ else if (tmp2 == -1)
+ tmp1 = -(uint32_t) tmp1;
+ else
+ tmp1 /= tmp2;
rl78_stack_push (tmp1, &status);
break;
case R_RL78_OPshla:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- tmp1 <<= tmp2;
+ if ((uint32_t) tmp2 >= 32)
+ tmp1 = 0;
+ else
+ tmp1 = (uint32_t) tmp1 << tmp2;
rl78_stack_push (tmp1, &status);
break;
case R_RL78_OPshra:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- tmp1 >>= tmp2;
+ if ((uint32_t) tmp2 >= 31)
+ tmp1 = tmp1 < 0 ? -1 : 1;
+ else
+ tmp1 >>= tmp2;
rl78_stack_push (tmp1, &status);
break;
@@ -534,13 +544,15 @@ rl78_compute_complex_reloc (unsigned long r_type,
case R_RL78_OPmod:
tmp2 = rl78_stack_pop (&status);
tmp1 = rl78_stack_pop (&status);
- if (tmp2 != 0)
- tmp1 %= tmp2;
- else
+ if (tmp2 == 0)
{
tmp1 = 0;
status = bfd_reloc_overflow;
}
+ else if (tmp2 == 1 || tmp2 == -1)
+ tmp1 = 0;
+ else
+ tmp1 %= tmp2;
rl78_stack_push (tmp1, &status);
break;
}
diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c
index 1421e443e51..68eb99fd392 100644
--- a/bfd/elf32-rx.c
+++ b/bfd/elf32-rx.c
@@ -1308,7 +1308,7 @@ rx_elf_relocate_section
case R_RX_OPneg:
{
- int32_t tmp;
+ uint32_t tmp;
saw_subtract = true;
RX_STACK_POP (tmp);
@@ -1319,7 +1319,7 @@ rx_elf_relocate_section
case R_RX_OPadd:
{
- int32_t tmp1, tmp2;
+ uint32_t tmp1, tmp2;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
@@ -1330,7 +1330,7 @@ rx_elf_relocate_section
case R_RX_OPsub:
{
- int32_t tmp1, tmp2;
+ uint32_t tmp1, tmp2;
saw_subtract = true;
RX_STACK_POP (tmp1);
@@ -1342,7 +1342,7 @@ rx_elf_relocate_section
case R_RX_OPmul:
{
- int32_t tmp1, tmp2;
+ uint32_t tmp1, tmp2;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
@@ -1357,29 +1357,46 @@ rx_elf_relocate_section
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 /= tmp2;
+ if (tmp2 == 0)
+ {
+ tmp1 = 0;
+ r = bfd_reloc_overflow;
+ }
+ else if (tmp2 == 1)
+ ;
+ else if (tmp2 == -1)
+ tmp1 = - (uint32_t) tmp1;
+ else
+ tmp1 /= tmp2;
RX_STACK_PUSH (tmp1);
}
break;
case R_RX_OPshla:
{
- int32_t tmp1, tmp2;
+ uint32_t tmp1, tmp2;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 <<= tmp2;
+ if (tmp2 >= 32)
+ tmp1 = 0;
+ else
+ tmp1 <<= tmp2;
RX_STACK_PUSH (tmp1);
}
break;
case R_RX_OPshra:
{
- int32_t tmp1, tmp2;
+ int32_t tmp1;
+ uint32_t tmp2;
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 >>= tmp2;
+ if (tmp2 >= 31)
+ tmp1 = tmp1 < 0 ? -1 : 1;
+ else
+ tmp1 >>= tmp2;
RX_STACK_PUSH (tmp1);
}
break;
@@ -1441,7 +1458,15 @@ rx_elf_relocate_section
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 %= tmp2;
+ if (tmp2 == 0)
+ {
+ tmp1 = 0;
+ r = bfd_reloc_overflow;
+ }
+ else if (tmp2 == 1 || tmp2 == -1)
+ tmp1 = 0;
+ else
+ tmp1 %= tmp2;
RX_STACK_PUSH (tmp1);
}
break;
@@ -1853,49 +1878,62 @@ rx_offset_for_reloc (bfd * abfd,
case R_RX_OPneg:
RX_STACK_POP (tmp1);
- tmp1 = - tmp1;
+ tmp1 = - (uint32_t) tmp1;
RX_STACK_PUSH (tmp1);
break;
case R_RX_OPadd:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 += tmp2;
+ tmp1 += (uint32_t) tmp2;
RX_STACK_PUSH (tmp1);
break;
case R_RX_OPsub:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp2 -= tmp1;
+ tmp2 -= (uint32_t) tmp1;
RX_STACK_PUSH (tmp2);
break;
case R_RX_OPmul:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 *= tmp2;
+ tmp1 *= (uint32_t) tmp2;
RX_STACK_PUSH (tmp1);
break;
case R_RX_OPdiv:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 /= tmp2;
+ if (tmp2 == 0)
+ tmp1 = 0;
+ else if (tmp2 == 1)
+ ;
+ else if (tmp2 == -1)
+ tmp1 = - (uint32_t) tmp1;
+ else
+ tmp1 /= tmp2;
RX_STACK_PUSH (tmp1);
break;
case R_RX_OPshla:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 <<= tmp2;
+ if ((uint32_t) tmp2 >= 32)
+ tmp1 = 0;
+ else
+ tmp1 = (uint32_t) tmp1 << tmp2;
RX_STACK_PUSH (tmp1);
break;
case R_RX_OPshra:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 >>= tmp2;
+ if ((uint32_t) tmp2 >= 31)
+ tmp1 = tmp1 < 0 ? -1 : 1;
+ else
+ tmp1 >>= tmp2;
RX_STACK_PUSH (tmp1);
break;
@@ -1937,7 +1975,12 @@ rx_offset_for_reloc (bfd * abfd,
case R_RX_OPmod:
RX_STACK_POP (tmp1);
RX_STACK_POP (tmp2);
- tmp1 %= tmp2;
+ if (tmp2 == 0)
+ tmp1 = 0;
+ else if (tmp2 == -1 || tmp2 == 1)
+ tmp1 = 0;
+ else
+ tmp1 %= tmp2;
RX_STACK_PUSH (tmp1);
break;
More information about the Binutils-cvs
mailing list