internal.c:
static void f(void);
void g(void)
{
f();
}
void main(void)
{
g();
}
external.c:
void f(void)
{
}
sdcc -c internal.c
sdcc -c external.c
sdcc internal.rel external.rel
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/r4k/r5k/r6k/sm83/tlcs90/ez80/z80n/r800/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502/mos65c02/f8/f8l TD- 4.5.24 #16456 (Mac OS X ppc)
SDCC links the two object files without reporting f as undefined. The call in internal.c is therefore resolved to the definition of f in external.c.
This is wrong. The file-scope declaration
static void f(void);
gives f internal linkage, therefore the declaration and use of f in internal.c cannot refer to the external-linkage function defined in external.c.
C23 6.9.1 paragraph 3 also requires exactly one external definition in the translation unit when an identifier declared with internal linkage is used in an expression. Here f is called in internal.c, but that translation unit contains no definition of it. (Confusingly, “external definition” means a definition appearing at file scope rather than meaning external linkage.)
The implementation is therefore required to diagnose internal.c. A definition of an external-linkage function named f in another translation unit must not satisfy this requirement or resolve the call.
For comparison, if external.rel is omitted, the linker reports:
?ASlink-Warning-Undefined Global _f referenced by module internal
Describing _f as a global symbol appears to reflect the underlying problem: SDCC has emitted an externally resolvable reference for an identifier that has internal linkage.
The relevant wording is in C23 6.2.2 paragraphs 2 and 3, and 6.9.1 paragraph 3:
I am attaching a candidate fix for this bug, created with assistance from Codex. I hope that it will prove acceptable when reviewed by SDCC's maintainers.
I did the following testing of the patch:
i.e.
make -j2
make -C support/regression clean-results
make -C support/regression -j2 test-ucz80
make -C support/valdiag clean
make -C support/valdiag -j2
Summary for 'ucz80': 0 failures, 36740 tests, 6407 test cases, 7347620 bytes, 1613638336 ticks
Summary for 'mcs51': 0 failures, 652 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-large': 0 failures, 650 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'mcs51-stack-auto': 0 failures, 651 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'ds390': 0 failures, 638 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'z80': 0 failures, 641 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'z180': 0 failures, 640 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'r2k': 0 failures, 640 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'r4k': 0 failures, 640 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'sm83': 0 failures, 640 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'tlcs90': 0 failures, 640 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'hc08': 0 failures, 639 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 's08': 0 failures, 639 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'mos6502': 0 failures, 639 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'stm8': 0 failures, 642 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'f8': 0 failures, 638 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'pdk13': 0 failures, 641 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'pdk14': 0 failures, 639 tests, 374 test cases, 0 bytes, 0 ticks
Summary for 'pdk15': 0 failures, 637 tests, 374 test cases, 0 bytes, 0 ticks