TL;DR How to use common (communal) symbols from C source code compiled with the OpenWatcom C compiler?
FYI Some introductions on common symbols (mostly GCC, so it doesn't answer my question about OpenWatcom):
I'm trying to use 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 -fcommon -s -O2 -o prog1 w1o.c
$ ./prog1o
FW1
$ gcc -fcommon -s -O2 -o prog12 w1o.c w2o.c
$ ./prog12o
FW2
Please note that this is non-standard behavior of GCC. The C standard says that both file-level mentions (one in w1o.c, one in w2o.c) are definitions of fwptr, and it's an error to have multiple definitions of the same symbol in a program. To make GCC follow the standard, use gcc -fno-common
(this will make it fail to compile). However, I need the opposite: in my program I need common symbols, so I'm using gcc -fcommon
.
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
Looking at the dmpobj output of w1o.obj, owcc has put fwptr to segment _BSS using a PUBDEF386 record.
To get a common symbol, we'd need a COMDEF record (see OMF intro). In fact, If I write w1o.c in assembly, and specify COMM _fwptr:DWORD:1
, wasm will create a COMDEF record, and the program works as expected:
$ wasm -q -fo=.obj w1oc.asm
$ owcc -s -O2 -o prog1o w1oc.obj clib3r.lib
$ ./prog1o
FW1
$ owcc -s -O2 -o prog12o w1oc.obj w2o.c clib3r.lib
$ ./prog12o
FW2
FYI here is the file w1oc.asm I used (containing COMM _fwptr:DWORD:1
):
.386p
.model flat
PUBLIC main_
COMM _fwptr:DWORD:1
EXTRN printf_:BYTE, __argc:BYTE, _cstart_:BYTE
DGROUP GROUP CONST
_TEXT SEGMENT PARA PUBLIC USE32 'CODE'
ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP
fw1_:
push offset FLAT:L$2
call near ptr FLAT:printf_
add esp,4
ret
mov eax,eax
main_:
mov eax,dword ptr FLAT:_fwptr
test eax,eax
je L$1
call eax
xor eax,eax
ret
L$1:
mov eax,offset FLAT:fw1_
call eax
xor eax,eax
ret
_TEXT ENDS
CONST SEGMENT DWORD PUBLIC USE32 'DATA'
L$2: DB 'FW1', 10, 0
CONST ENDS
END
It looks like wasm and wlink support common symbols, but the OpenWatcom C compiler (wcc386) doesn't. Or am I using it incorrectly?