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.