PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 1/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs RESOLVING SEGMENT/GROUP xxxx EXCEEDS 64K MESSAGES ================================================= To resolve errors reporting 'Segment/Group etc. exceeds 64K', one must first identify the contributors to the segment/group and then proceed to decrease the size of the segment/group. NOTE: One could also get a 'Group exceeds 64K message' resulting from incorrect ordering of segments. For example, DGROUP could exceed 64K if a new segment is introduced (usually done in assembly modules) and grouped in DGROUP without the usage of a proper segment CLASS. However, this occurence is fairly rare and, in most cases, a group exceeds 64K because the sum of the segments making up the group do in fact exceed 64K. ( Examine a detail MAP files to identify cases where a mis- ordering of segments is at the root of the problem - A typical case would involve a new segment ordered after the STACK segment but incorrectly grouped into DGROUP ). Since each segment or group is limited to 64K in size, resolving our problem obviously involves decreasing the items inserted in the segment/group. The following section will identify the most frequent causes for both DOS and Windows applications. Several of the issues and their solutions are common to both environments. Before proceeding to the common issues/solutions, however, first generate a 'Detail MAP File' of your application and identify the various modules and .OBJs/LIBs which are contributing data/code to the segment/group whose size currently exceed 64K. Identifying the contributors to the segment/group will help you better understand which common cause(s) listed below best describes your case. DOS & WINDOWS PROGRAMMING: ========================== (a) JUST PLAIN TOO MUCH GLOBAL DATA. ==================================== The main contributor to the Data Segments ( DGROUP/ or Automatic Data Segment ) is static/global data. Hence, one way to resolve the 64K limitation is to decrease the amount of global data inserted in the AUTOMATIC DATA SEGMENT. The compiler PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 2/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs. inserts every static and global variables in either the _BSS or _DATA segments. For example: // Global variable... int array[10]; // Space is allocated in // DGROUP/Default data segment The array defined above contributes '10 * sizeof( int )' bytes to DGROUP. A large number of small such variables or a few bigger ones can easily cause _BSS, _DATA or DGROUP to exceed 64K. The solution is to inform the compiler to allocate space for the variables in a separate ( or far ) data segments. For example, the above would be recoded as: // Global variable int far array[10]; // Space is allocated in a // far data segment The use of the far keyword before the variable name causes the compiler to use a far data segment when allocating space for the variable. To compel the compiler to place variables in a separate/far data segment, one can also set a fairly low 'far data threshold' and enable automatic far data. (These options are found under Options | Compiler | Advanced code generation; use a -Ff=xxx when using the command line compiler). Variables whose sizes are are equal to or exceed the threshold will automatically be put in a far data segment. NOTE: The 'Far Data Threshold' solution can only help if the application declares large global variables. Large global variables part of an .OBJ or .LIB have already been assigned a segment location when they were compiled. (b) TOO MUCH CONSTANT STRINGS. ============================= Constant strings go into the data segment by default; furthermore they are *not* listed in a detailed MAP file. Therefore one could examine a detail map file and not be able to account for a big chunk of DGROUP that does not seem to be occupied by any variable declared by the programmer: watch out for constant strings!! For example: MessageBox( GetFocus(), "Hello", "Caption", MB_OK ); PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 3/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs. The above code will use 14 bytes in the data segment for the strings "Hello" and "Caption" (the size includes the null terminators for the strings as well). Constant strings are unaffected by the 'FAR DATA THRESHOLD' settings and can be moved to far data segments by using a far variable; The above would thus be recoded as: char far szHello[] = "Hello"; char far szCaption[] = "Caption"; MessageBox( GetFocus(), szHello, szCaption, MB_OK ); NOTE: Windows applications may take advantage of String-Table resources for constant strings. For more info. see the WINDOWS ISSUES section below. (c) COMPILER GENERATED TABLES ============================= If you are using the C++ language, the compiler will automatically generate virtual tables for classes containing virtual functions. These tables are stored in the data segment by default. You can confirm the location of vtables by inspecting a map file. The public name of a virtual table is 'ClassName::', where ClassName is the name of the class containing virtual functions. In a program with several classes, the vtables can occupy a lot of space. You can force the compiler to generate far vtables to make more room in the default data segment. The -Vf option can be used from the command line tools. In the IDE, use the OPTIONS|COMPILER|C++ OPTIONS dialog. Far vtables are placed in the code segment, so they will not affect the number of instances of the application that can be launched. ( NOTE: Windows allows only one instance of any application containing FAR DATA segments ). Object Windows Application have even bigger virtual tables since the DDVT mechanism is implemented as an extension of the virtual table - See the WINDOWS ISSUES section below for more information on how to use far virtual tables with the Object Windows Library. (d) INAPPROPRIATE MEMORY MODEL ============================== PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 4/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs. Changing memory models can often resolve problems regarding 'Segment/Group xxxx exceed 64K'. A good understanding of the various segments generated for each memory model will often help in those cases. See your 'Programmer's Guide' for an explanation of the distinct segment layout of the various memory model. Below is a list of frequent scenarios: MESSAGE SOLUTION - _TEXT exceeds 64K Use a memory model with multiple CODE segments: Medium, Large or Huge ( Huge for DOS only ). - _DATA exceeds 64K Use a memory model with multiple DATA segments: Huge. ( Huge for DOS only - See. items (a), (b) and (c) above and Windows specific issues mentioned below for Windows Applications ). DOS ISSUES: =========== (a) USING registerbgidriver()/registerbgifont(). ================================================ The Borland Graphics Engine allows one to link in video drivers and/or fonts after the latter have been converted to .OBJ files using the BGIOBJ.EXE utility. Linking several fonts and/or drivers may cause _TEXT to exceed 64K. To resolve this issue, use registerfarbgidriver() and registerfarbgifont() instead and use the /f option when using BGIOBJ. [ See the BGIOBJ documentation for more information ]. WINDOWS ISSUES ============== The AUTOMATIC DATA SEGMENT (ADS) of a Windows application contains global and static variables ( commonly referred to as DGROUP ), the requested Local Heap and the application's Stack irrespective of the memory model used!. The size of the local heap and stack are controlled by the HEAPSIZE and STACKSIZE keywords in the module definition file (.DEF file). PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 5/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs. Since the sum of the three items mentioned above cannot exceed 64K, the solution is to decrease the size of one or more of the contributors to the Automatic Data Segment. Decreasing the amount of data contributing to the ADS is covered in the DOS/WINDOWS combined issues above. The workarounds specific to Windows application involve reducing the stack and/or heap size requirement specified in the application DEF file and use String-Table resources. A String-Table resource can be used to store NULL terminated strings which can be loaded at runtime. String-Tables can greatly reduce the size of DGROUP and allow for easier code maintenance and customization, such as International support. Using String-Tables requires the use of an extra API call [LoadString()]; however, the benefits may outweigh this 'inconvenience'. In Windows 3.0 and 3.1, the HEAPSIZE can be reduced to a minimum size of 256 bytes. This is the size of the local heap. When you are in the LARGE or COMPACT memory model, the near heap is used by neither the malloc family of functions nor the new operator, so one does not need a large near heap in the mentioned memory models. In SMALL or MEDIUM, however, the C/C++ allocation routines use the local heap; decreasing the HEAPSIZE may cause runtime memory allocations to fail. ( NOTE: It is often mentioned that the Large memory model should be avoided when writing Windows applications; this statement does *NOT* apply to Borland's Large memory model but rather to tools providing multiple data segments in the Large memory model, such as the Microsoft C++ Compiler. It is perfectly OK to use the Large Memory model for Windows development when using the Borland C++ Compiler and Tools ). Reducing the STACKSIZE will also help although one has to ascertain that enough stack is available at runtime. Various tools of determining stack usage are available from BBS and CompuServe. Most projects determine a safe value based on the amount of local variables, presence of recursion and levels of nesting in function calls. Note that a minimum of 5120 bytes of STACK must be used. To use Far Virtual Tables with an ObjectWindows program (OWL), you must link with the dynamic versions of the libraries. PRODUCT : Borland C++ NUMBER : 703 VERSION : All OS : ALL DATE : October 19, 1993 PAGE : 6/1 TITLE : Resolving "Segment or Group xxxx Exceeds 64K" msgs. The requirements for using the DLL version of OWL are discussed in the Object Windows Users Manual, and outlined below: - define _CLASSDLL, - use Large model, - use smart callbacks for entry exit code when building the EXE ( all functions or explicit functions exported for a DLL ) - use case sensitive exports as a linker option. - Link to the dynamic version of the OWL, Container, and Run time libraries. ADDITIONAL NOTES: ================= If you need more information about the various tables and data of a MAP file, request document #1320 ( from Borland's TechFax at 1-800-822-4269 ) which covers MAP files' contents in detail. If you have access to a modem, you may want to download a copy of FARSTR.ZIP from the Borland BBS ( 408-439-9096 ). This utility can be used to create far variables where constants strings are current used. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.