[net.micro.pc] Compiling Really Large Programs With Microsoft C V3.0

cramer@kontron.UUCP (Clayton Cramer) (02/20/86)

This is a helpful hint to those of you building really big programs
on the IBM using Microsoft C V3.0.

We have a large piece of C that we are developing simultaneously on
a VAX and IBM AT -- roughly 40,000 lines of C, all linked together,
no overlays.  Unlike a lot of commercial products, our program has
very large quantities of static data.  (Your average spreadsheet has
know problem gobbling up to and beyond 640K, but most of the memory
is allocated -- not static.)

If you don't read the Microsoft C manual in excruciating detail, you
would think that compiling in large model (/AL on the command line)
would be adequate for the largest program that will fit into the 
address space.  Not so!  From section 8.1.1.2 of the Microsoft C
Compiler User's Guide:

  All segments with the same group name must fit into a single 
  physical segment, which is up to 64K bytes long.  This allows all
  segments in a group to be accessed through the same segment 
  register.  The Microsoft C compiler defines one group named
  DGROUP.
  
  The NULL, _DATA, CONST, BSS, c_common, and STACK segments are
  grouped together in the data group, called DGROUP.  This allows
  the compiler to generate code for accessing data in each of these
  segments without constantly loading the segment values or using
  many segment overrides on instructions.  DGROUP is addressed
  using the DS or SS segment register.  DS and SS always contain
  the same value except when the "u" or "w" option of the /A
  option is used.
  
As you can see by table 8.1 that follows in the same manual, even
a large model program will try to put all the global and static
data into one group, and that one group will be entirely in a 
64K segment.  The symptom is "fixup overflow near <address> in
segment <name> in <file>.OBJ(<file>) offset <offset>" messages 
from the linker.

The section quoted above might tempt you to use an option like
/Alfu to allocate different segments for the stack and the
data segments.  In fact, this is what I tried first, and for
reasons that are not immediately obvious, our program stopped
dead in its track, looping endlessly.

What does work is to use the options /AL and /Gt.  From section
7.12 of the User's Guide:

  /Gt [<n>]

  By default, the compiler allocates all static and global data
  items to the default data segment.  The /Gt option causes all 
  data items greater than <n> bytes to be allocated to a new 
  data segment.
  
The effect is to create separate segments AND GROUPS for each
module's static and global data.  This doubtless requires more
setting of segment registers -- but I can't see any obvious 
slowing of our program after recompiling with the /Gt option.

One other item: a very large program will quickly exceed 128 
segments, which is the default number of segments the Microsoft
Linker likes to work with.  Use the /SEGMENTS:<nbr> option on the
link to deal with this.