5.54 Integer division-by-zero errors in C code

For targets that do not support hardware division instructions (for example SDIV and UDIV), you can trap and identify integer division-by-zero errors with the appropriate C library helper functions, __aeabi_idiv0() and __rt_raise().

Trapping integer division-by-zero errors with __aeabi_idiv0()

You can trap integer division-by-zero errors with the C library helper function __aeabi_idiv0() so that division by zero returns some standard result, for example zero.

Integer division is implemented in code through the C library helper functions __aeabi_idiv() and __aeabi_uidiv(). Both functions check for division by zero.

When integer division by zero is detected, a branch to __aeabi_idiv0() is made. To trap the division by zero, therefore, you only have to place a breakpoint on __aeabi_idiv0().

The library provides two implementations of __aeabi_idiv0(). The default one does nothing, so if division by zero is detected, the division function returns zero. However, if you use signal handling, an alternative implementation is selected that calls __rt_raise(SIGFPE, DIVBYZERO).

If you provide your own version of __aeabi_idiv0(), then the division functions call this function. The function prototype for __aeabi_idiv0() is:

int __aeabi_idiv0(void);

If __aeabi_idiv0() returns a value, that value is used as the quotient returned by the division function.

On entry into __aeabi_idiv0(), the link register LR contains the address of the instruction after the call to the __aeabi_uidiv() division routine in your application code.

The offending line in the source code can be identified by looking up the line of C code in the debugger at the address given by LR.

If you want to examine parameters and save them for postmortem debugging when trapping __aeabi_idiv0, you can use the $Super$$ and $Sub$$ mechanism:

  1. Prefix __aeabi_idiv0() with $Super$$ to identify the original unpatched function __aeabi_idiv0().

  2. Use __aeabi_idiv0() prefixed with $Super$$ to call the original function directly.

  3. Prefix __aeabi_idiv0() with $Sub$$ to identify the new function to be called in place of the original version of __aeabi_idiv0().

  4. Use __aeabi_idiv0() prefixed with $Sub$$ to add processing before or after the original function __aeabi_idiv0().

The following example shows how to intercept __aeabi_div0 using the $Super$$ and $Sub$$ mechanism.

extern void $Super$$__aeabi_idiv0(void);
/* this function is called instead of the original __aeabi_idiv0() */
void $Sub$$__aeabi_idiv0()
{
    // insert code to process a divide by zero
    ...
    // call the original __aeabi_idiv0 function
    $Super$$__aeabi_idiv0();
}

Trapping integer division-by-zero errors with __rt_raise()

By default, integer division by zero returns zero. If you want to intercept division by zero, you can re-implement the C library helper function __rt_raise().

The function prototype for __rt_raise() is:

void __rt_raise(int signal, int type);

If you re-implement __rt_raise(), then the library automatically provides the signal-handling library version of __aeabi_idiv0(), which calls __rt_raise(), then that library version of __aeabi_idiv0() is included in the final image.

In that case, when a divide-by-zero error occurs, __aeabi_idiv0() calls __rt_raise(SIGFPE, DIVBYZERO). Therefore, if you re-implement __rt_raise(), you must check (signal == SIGFPE) && (type == DIVBYZERO) to determine if division by zero has occurred.

Non-ConfidentialPDF file icon PDF versionARM DUI0472M
Copyright © 2010-2016 ARM Limited or its affiliates. All rights reserved.