0

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?

pts
  • 80,836
  • 20
  • 110
  • 183
  • "common (communal) symbols" is not C terminology or a C thing as far as I know. Perhaps you are coming from a different programming language. (FORTRAN?) Or perhaps you are trying to use some WATCOM C extension that is not part of standard C? – Avi Berger May 22 '23 at 00:12
  • @AviBerger: OpenWatcom uses the OMF (.obj file) format for object files. COMDAT is an OMF record, https://en.wikipedia.org/wiki/Relocatable_Object_Module_Format says *uninitialized common data*. The description of the OMF file format (http://www.azillionmonkeys.com/qed/Omfg.pdf) says *communal names*. See also this very detailed description about how common symbols are used by GCC (with C code): http://www.azillionmonkeys.com/qed/Omfg.pdf – pts May 22 '23 at 00:21
  • 2
    In standard C there are variable declarations and definitions. Variable declarations are qualified by extern, are normally contained in header files that are included in .c files and declare that the thing exists, but does not create it. Variable definitions are not qualified by extern, may or may not have an initializer, and there can only be one of them per program per variable. These are normally contained in .c files. – Avi Berger May 22 '23 at 00:22
  • @AviBerger: Thank you for spelling out the basics of how variable declarations and definitions work in standard C. It looks like that a *common symbol* is not a standard C concept. Nevertheless, it's supported by multiple toolchains (1. GCC: gcc + as + ld; 2. OpenWatcom: wasm + wlink), and in this question I'm asking about support in the OpenWatcom C compiler. It's nice to know that the C standard doesn't mention this concept, but it doesn't answer my question. – pts May 22 '23 at 00:26
  • Sorry, that's outside of standard C. Have to check the WATCOM documentation to see if it has an extension to deal with that. I don't have a copy of those docs. – Avi Berger May 22 '23 at 00:27
  • OpenWatcom C docs: 1. https://open-watcom.github.io/open-watcom-v2-wikidocs/cguide.html 2. https://open-watcom.github.io/open-watcom-v2-wikidocs/clr.html . Neither mentions common symbols. But maybe they are documented elsewhere or undocumented. – pts May 22 '23 at 00:45

2 Answers2

0

As a workaround, I can use extern in my C source file w1o.c, and create custom .asm file with the comm _fwptr:DWORD:1. This works:

/* w1o.c */
#include <stdio.h>
extern void (*fwptr)(void);  /* See w1sc.asm for a COMM definition. */       
static void fw1(void) { printf("FW1\n"); }
int main(int argc, char **argv) {
  (void)argc; (void)argv;
  (fwptr ? fwptr : fw1)();
  return 0;
}
; w1sc.asm
COMM _fwptr:DWORD:1
/* w2o.c */
#include <stdio.h>
static void fw2(void) { printf("FW2\n"); }
void (*fwptr)(void) = fw2;

It works:

$ wasm -q -mf -fo=.obj w1sc.asm
$ owcc -s -O2 -o prog1o  w1o.c w1sc.obj
$ ./prog1o
FW1
$ owcc -s -O2 -o prog12o w1o.c w1sc.obj w2o.c
$./prog12o 
FW2

However, this is still a workaround, I'd like to do everything in C source code, if possible.

pts
  • 80,836
  • 20
  • 110
  • 183
0

Watcom is clearly wrong here. I am surprised, we used them as a compiler vendor for a while decades ago. They were certainly more interested in the micro-optimisation of the day; but weren't generally this bad.

Your expectations were correct. This implementation is not.

IIRC, the actual watcom crew ran away when sybase got control of them. It isn't so much open source as abandon-ware.

mevets
  • 10,070
  • 1
  • 21
  • 33