The R3.5 version of ic960 provides a new option, -G{dc|ds}, which permits the user to select whether common symbol definitions (dc) should be emitted for uninitialized externs or whether these common symbol definitions should be suppressed (ds). If unspecified, the default is -Gdc.
The -Gds feature provides the user with the ability to easily assign global data (uninitialized externs) to specific memory addresses at link time. This feature did not exist in the R3.0 version of ic960 and a workaround for that version is discussed in the March 1991 issue of ;Comments.
First, we'll define some terms for use in this article. An "uninitialized extern" is a type of symbol whose definition appears outside of a function block, i.e., not enclosed within curly braces, which has no initialization value(s) and which has not necessarily been declared as "extern".
In the example below, the variable "xyz" is an uninitialized extern symbol; in this case a defining instance of a global variable. It is global because it appears outside of curly braces; it is a defining instance because the keyword "extern" is absent; and it has no initial value, hence it is uninitialized.
int xyz;
void foo(void) {
xyz++;
}
Remember that there is a difference between a definition of a symbol and a reference to a symbol. The reference to an external symbol in a prototype is preceded by the keyword "extern", while the definition of an external symbol is not.
A "common symbol definition" is one method that the compiler can use to allocate storage for a defining instance of an uninitialized extern symbol, where the symbol, after a final link, ultimately occupies the same addresses in memory as all other identical defining instances of the same symbol. FORTRAN programmers will recognize this as being similar to a FORTRAN common block.
In an application where a module defines an uninitialized extern, by default the compiler will emit a common symbol definition by placing the symbol in a temporary section named ".comm". This is easily demonstrated by the following example. Given the one-line source file, foo.c:
When compiled with "ic960 -S", the following assembler mnemonics are emitted, which are subsequently assembled:
However, as an aside, the following linking possibilities also exist:
The iC960 R3.5 feature -Gds tells the compiler to place the uninitialized extern(s) in the ".bss" section in the object module(s) subsequently output by the assembler. The linker will permit the user to control the address assignments for incoming ".bss" sections. The same source file, foo.c, when compiled with "ic960 -S -Gds":
MEMORY { one: o=0x10000000,l=0x200000 two: o=0x10200000,l=0x1cffff } SECTIONS { GROUP : { .text : { } .data : { } .bss : { } } > one foosec : { foo.o(.bss) } > two }It should be noted that compiling with "ic960 -Gds" presents a limitation of its own; of the modules compiled with -Gds, there can now only be ONE defining instance of the uninitialized extern in the entire application. All other appearances of the extern in other modules compiled with -Gds must be references only, i.e, they all must be preceded by the keyword "extern". For example:
Otherwise, the linker won't properly resolve all references to the single range of memory addresses specified in the linker directive file.
In summary, using the iC960 R3.5 -Gds switch will allow the user complete control over the assignment of global data to memory, via the linker directive file, whereas omitting the -Gds switch from the compiler's invocation will cause all uninitialized externs to end up in the default .bss section.
Legal Stuff © 1997 Intel Corporation