Copyright 1984 by ABComputing ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º A Question of Size º º º º by º º º º Richard Levaro º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Introduction ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Three of the most popular C Compilers (Lattice, Computer Innovations and Digital Research) have implemented so-called large memory models. Much has been made of the different memory models, but a qualitative evaluation of their use has not been published in the more well known (if not encyclopedic) trade press. MS-Pascal (and IBM Pascal) implement a "large" memory model, which we believe is the most appropriate. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Memory Models ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Because of the segmented nature of the Intel 8086 family architecture, compiler designers must choose a particular memory model or allocation scheme when designing the code generation phase. The details of how data is stored, where code is placed, and calling conventions vary from compiler to compiler, but there are four basic possibilities: 1. Small Model - A single segment is reserved for code, and one is reserved for data. Consequently, programs can be no larger than 128K, 64K for data and 64K for code. In the early days of the IBM PC and MS-DOS, it was a common misconception (propagated by many of the leading "experts" writing in the trade press) that the IBM Pascal Compiler used this model. 2. Large Code Model - Multiple segments can be used for code (however, each compiland, e.g., module, unit, or function, can be at most 64K), but all data is restricted to one segment. This model is used by the MS-Pascal and IBM Pascal compilers. The size of the program code is restricted only by the linker (and of course, available real memory), because many separately compiled pieces can be linked together. 3. Large Data Model - A single segment is reserved for code, but multiple segments are used for data. Implementations vary, but often one segment is used for constants and static variables (pointed to by the DS register), another segment for the stack (pointed to by SS), and the remainder of memory used for the heap (dynamically allocated variables). 4. Large Model - Multiple segments are used for both code and data; this model is a combination of the Large Code and Large Data models. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Advantages and Overhead ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ What are the relative advantages and overhead of the various models? Fundamentally, the impact is in two areas: how procedures and functions are called, and how data addresses (pointer values) are calculated. There are two ways to call a procedure: near or far calls. A near call assumes the routine being called is in the same code segment as the call instruction. Only the instruction pointer value (in the IP register) need be saved in anticipation of the return. A far call must save both the code segment (CS register) and the instruction pointer to prepare for the return. The overhead for a far call (and subsequent return) is not much more than for a near call. Therefore, the large code models allow one to write large programs without overwhelming overhead. Large data models involve a different overhead. Basically, if data resides in separate segments, both a segment and offset must be calculated. Address arithmetic, which is one of the most frequent computations, now requires two 16-bit words instead of just one. An inelegant implementation of a large data model can disastrously affect program performance. The advantage of a large data model is principally the ability to store very large data structures (for example, arrays). It is rarely that a 64K stack space is required. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ MS-Pascal and IBM Pascal ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Microsoft MS-Pascal and IBM Pascal use the large code model, but the compiler supports a data type (the ADS type) which makes it possible to use all available memory. The tradeoff is that execution speed is not overwhelmed by the large data model overhead, but if extra data space is needed, the address type can be used to implement it. In our view, this is the most sensible solution: In most cases 64K of data is acceptable. Larger data requirements should be regarded as an exceptional case. Using the ADS type is very similar to the standard pointer, except instead of using the NEW procedure to allocate space on the standard heap it must be done directly. MS-Pascal Version 3.11, and later versions, support a library function to allocate space beyond the standard heap. Space can be allocated using DOS 2.0 function calls as well. The program SPACE ( in file list1.pas on this diskette) shows how to use the MS-Pascal ALLMQQ function to allocate space, and the ADS type to access the data structure. The contents of file list1.pas are reproduced below: {**********************************************************************} { } { SPACE Example illustrating the use of the ADS type for addressing } { data beyond the 64K data space. Storage for the record type } { is allocated using the external MS-Pascal function ALLMQQ, } { and the returned segment address is assigned to the ADS } { variable. } {______________________________________________________________________} program space(input,output); type comdata = record msg_no : integer; msg_cnt : integer; msg : lstring(128) end; var comdata_ptr : ads of comdata; function allmqq(no_bytes : word) : adsmem; external; begin {space} comdata_ptr := allmqq(132); ! Segment, offset address of record comdata_ptr^.msg_no := 1; comdata_ptr^.msg_cnt := 0; comdata_ptr^.msg := 'Hello World'; if (comdata_ptr^.msg_no > 0) then writeln(output,comdata_ptr^.msg); end. {space} ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ File Name: ÛÛ pas1.txt ÛÛ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ice used to view information. There are