If the variable has a null value and the call is invalid then the compiler isn't required to compile it to anything specific; this includes the idea that the compiler isn't required to compile it to a jump-to-address-zero.
> the compiler isn't required to compile it to anything specific
That might be true if the ISO C standard were the only source of requirements going into the making of that compiler; it isn't.
There are other issues.
Obviously, the compiler is in fact compiling it to something very specific. It's not simply an accident due to the situation being ignored that the indirect call gets replaced by a direct jump. The translation is deliberate.
From ISO C: Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
This is definitely not the result of "ignoring the situation completely"; ignoring the situation completely means translating the code earnestly and subsequently the translation doing the indirect jump attempt through a null pointer. That's what it means not to do anything specific. It's not terminating the translation, so it's not the third kind of behavior. So it must be "behaving during translation or programing execution in a documented manner characteristic of the environment". I don't see how this is a characteristic of the environment; nobody can claim with a straight face that this is environmentally dictated!
Also, the undefined behavior never actually occurs. A pointer variable may be null; null is a valid value. Undefined behavior only ensues when the attempt is made to dereference. That's not actually happening in the program; the translation is devoid of any attempt to dereference null. The idea that the null pointer dereference caused the translation and the subsequent call to that function requires a perverted view of causality in which later events cause earlier events.
There are two possibilities the compiler is faced with, that the function pointer is null or that the external function was called and the function pointer is set to a concrete function.
Since the null pointer option would lead to undefined behavior at runtime (no one is confusing cause and effect here) the compiler can ignore this case.
That leaves only one choice, and that's the result of the compilation.