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.
@@ -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;
}
}
@@ -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;
}
@@ -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;