PREV UP NEXT Using and Porting GNU CC

10.2: Global Declarations and VMS

GNU CC does not provide the globalref, globaldef and globalvalue keywords of VAX-C. You can get the same effect with an obscure feature of GAS, the GNU assembler. (This requires GAS version 1.39 or later.) The following macros allow you to use this feature in a fairly natural way:

#ifdef __GNUC__
#define GLOBALREF(TYPE,NAME)                      \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME)
#define GLOBALDEF(TYPE,NAME,VALUE)                \
  TYPE NAME                                       \
  asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME) \
    = VALUE
#define GLOBALVALUEREF(TYPE,NAME)                 \
  const TYPE NAME[1]                              \     
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)
#define GLOBALVALUEDEF(TYPE,NAME,VALUE)           \
  const TYPE NAME[1]                              \
  asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)  \
    = {VALUE}
#else
#define GLOBALREF(TYPE,NAME) \
  globalref TYPE NAME
#define GLOBALDEF(TYPE,NAME,VALUE) \
  globaldef TYPE NAME = VALUE
#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
  globalvalue TYPE NAME = VALUE
#define GLOBALVALUEREF(TYPE,NAME) \
  globalvalue TYPE NAME
#endif

(The _$$PsectAttributes_GLOBALSYMBOL prefix at the start of the name is removed by the assembler, after it has modified the attributes of the symbol). These macros are provided in the VMS binaries distribution in a header file `GNU_HACKS.H'. An example of the usage is:

GLOBALREF (int, ijk);
GLOBALDEF (int, jkl, 0);

The macros GLOBALREF and GLOBALDEF cannot be used straightforwardly for arrays, since there is no way to insert the array dimension into the declaration at the right place. However, you can declare an array with these macros if you first define a typedef for the array type, like this:

typedef int intvector[10];
GLOBALREF (intvector, foo);

Array and structure initializers will also break the macros; you can define the initializer to be a macro of its own, or you can expand the GLOBALDEF macro by hand. You may find a case where you wish to use the GLOBALDEF macro with a large array, but you are not interested in explicitly initializing each element of the array. In such cases you can use an initializer like: {0,}, which will initialize the entire array to 0.

A shortcoming of this implementation is that a variable declared with GLOBALVALUEREF or GLOBALVALUEDEF is always an array. For example, the declaration:

GLOBALVALUEREF(int, ijk);

declares the variable ijk as an array of type int [1]. This is done because a globalvalue is actually a constant; its ``value'' is what the linker would normally consider an address. That is not how an integer value works in C, but it is how an array works. So treating the symbol as an array name gives consistent results---with the exception that the value seems to have the wrong type. Don't try to access an element of the array. It doesn't have any elements. The array ``address'' may not be the address of actual storage.

The fact that the symbol is an array may lead to warnings where the variable is used. Insert type casts to avoid the warnings. Here is an example; it takes advantage of the ANSI C feature allowing macros that expand to use the same name as the macro itself.

GLOBALVALUEREF (int, ss$_normal);
GLOBALVALUEDEF (int, xyzzy,123);
#ifdef __GNUC__
#define ss$_normal ((int) ss$_normal)
#define xyzzy ((int) xyzzy)
#endif

Don't use globaldef or globalref with a variable whose type is an enumeration type; this is not implemented. Instead, make the variable an integer, and use a globalvaluedef for each of the enumeration values. An example of this would be:

#ifdef __GNUC__
GLOBALDEF (int, color, 0);
GLOBALVALUEDEF (int, RED, 0);
GLOBALVALUEDEF (int, BLUE, 1);
GLOBALVALUEDEF (int, GREEN, 3);
#else
enum globaldef color {RED, BLUE, GREEN = 3};
#endif