I have two C source files:
/* w1.c */
#include <stdio.h>
__attribute__((weak)) void fw(void) { printf("FW1\n"); }
int main(int argc, char **argv) {
(void)argc; (void)argv;
fw();
return 0;
}
/* w2.c */
#include <stdio.h>
void fw(void) { printf("FW2\n"); }
If I compile and run them with gcc, FW1 or FW2 is printed, depending on whether w2.c is used:
$ gcc -s -O2 -o prog1 w1.c
$ ./prog1
FW1
$ gcc -s -O2 -o prog12 w1.c w2.c
$ ./prog12
FW2
This works like this because in w1.c the symbol fw is weak, so it gets ignored iff another file (i.e. w2.c) defines a non-weak symbol with the same name.
Thuse the mere presence of w2.c can modify the behavior of w1.c, through a weak symbol defined in w1.c.
Is there something likes this with the OpenWatcom C compiler? What is the syntax insteda of __attribute__((weak))
? Simply omitting __attribute__((weak))
won't work, because linking will fail because of the duplicate symbol. I want the compiler commands and programs ./prog1
and ./prog12
) above work with owcc
instead of gcc
, and possibly adding some flags.
I need this because I want to implement a cleanup mechanism (calling function fw) which should be replaced automatically with something more sophisticated if additional source (or object) files are also used. Thus I'd need two implementations of the cleanup mechanism (simple fw in w1.c, sophisticated fw in w2.c).
I also considered using common symbols (i.e. those which can be defined in multiple files as long as at most one file has a nonzero definition). Here are my source files, with the common symbol being fwptr:
/* w1o.c */
#include <stdio.h>
void (*fwptr)(void);
static void fw1(void) { printf("FW1\n"); }
int main(int argc, char **argv) {
(void)argc; (void)argv;
(fwptr ? fwptr : fw1)();
return 0;
}
/* w2o.c */
#include <stdio.h>
static void fw2(void) { printf("FW2\n"); }
void (*fwptr)(void) = fw2;
As expected, if I compile and run them with gcc, FW1 or FW2 is printed, depending on whether w2o.c is used:
$ gcc -s -O2 -o prog1 w1o.c
$ ./prog1o
FW1
$ gcc -s -O2 -o prog12 w1o.c w2o.c
$ ./prog12o
FW2
However, OpenWatcom doesn't allow multiple definitions of a symbol:
$ owcc -s -O2 -o prog1o w1o.c
$ ./prog1o
FW1
$ owcc -s -O2 -o prog12o w1o.c w2o.c
Warning! W1027: file w2o.o(/tmp/w2o.c): redefinition of _fwptr ignored
$ ./prog12o
FW1
Here is what's going on with GCC:
/* symbol.c */
int sym0 = 0;
int sym1 = 1;
int sym2;
extern int sym3;
int func() { return sym0 + sym1 + sym2 + sym3; }
$ gcc -fno-pic -m32 -Os -c -o symbol.o symbol.c
$ readelf -a symbol.o
...
Num: Value Size Type Bind Vis Ndx Name
... 8: 00000000 28 FUNC GLOBAL DEFAULT 1 func
9: 00000000 4 OBJECT GLOBAL DEFAULT 3 sym1
10: 00000000 4 OBJECT GLOBAL DEFAULT 4 sym0
11: 00000004 4 OBJECT GLOBAL DEFAULT COM sym2
12: 00000000 0 NOTYPE GLOBAL DEFAULT UND sym3
As seen above, sym3 (the common one) is different from the others, and at link time we use this to provide an alternative definition.
When compiling the same code with OpenWatcom owcc, and dumping the .obj file with OpenWatcom dmpobj, I get:
- sym0: EXTDEF (type 0), PUBDEF386 (type 0), LEDATA386: 4 bytes in segment _DATA
- sym1: EXTDEF (type 0), PUBDEF386 (type 0), LEDATA386: 4 bytes in segment _DATA
- sym2: EXTDEF (type 0), PUBDEF386 (type 0), 4 bytes in segment _BSS
- sym3: EXTDEF (type 0), no PUBDEF386, no definition in _DATA or _BSS
I have asked a new question about common symbols with OpenWatcom: Support for common symbols in OpenWatcom C compiler