Using arm-none-eabi-gcc, the following program gives a different output depending on compiler optimisation level:
#include <stdio.h>
unsigned short p = 100;
void f(signed char o) {
    // o is signed, so 0xfc should be interpreted as -4 here, but it is not always
    p += o;
}
int main(void) {
    void (*fp)(unsigned char o);
    fp = (void (*)(unsigned char))f;
    printf("%d\n", p);
    fp(0xfc);
    printf("%d\n", p);
    return 0;
}
Output with -O0 (desired):
    100
    96
Output with -O2 (undesired):
    100
    352
I wish for the program to output 96, when using -O2.
Using -fwrapv, or -fno-strict-overflow has no affect.
I cannot change the type of fp, I want f to always interpret the first parameter as a signed char (so it sees 0xfc as -4).