• Keine Ergebnisse gefunden

Program Segmentation

Im Dokument Standards Programming (Seite 187-194)

Generally, a program is written in several separate source files. Each of these source files is compiled into an object module. An object module is composed of one or more segment elements of different classes. The classes used in an object module are typically code, static data, constant data, and stack.

When the object modules are linked, the Linker follows a set of ordering rules to generate a run file. The Linker sorts and recombines the segments in each object module by class to produce larger linker segments. From this point on, these linker segments are referred to simply as segments.

(For a more detailed discussion of the Linker's function, see your operating system documentation.)

When the program executes, each of these segments receives a unique selector, which identifies the area of memory in which that segment resides. When the program calls a procedure or accesses data, the processor updates its registers, so that the called procedure or data can be addressed.

If the new address is in the same segment at the previously-used one, the processor only needs to update the register that contains the offset of the requested item. When only the offset must be changed, the event is called a near reference (for data) or a near call (for a procedure).

If the new address is in a different segment from the previously-used one, the processor must load both the selector and the offset of the desired item. This requires the processor to change the contents of two registers, instead of one. This requires more time than changing just the offset.

When both the segment and the offset must be changed, the event is called afar reference (for data) or afar call (for a procedure).

10-2 eTOS/ Open Programming Practices and Standards - Part II

Most programs that run under CTOS use the medium model of segmentation. In the medium model, all calls are far and all references to static data and the stack are near.

Memory Organization The Medium Model

As noted in the previous section, the medium model of segmentation is the most common one used by CTOS programs. One of the requirements of the medium model is that the total size of the program's static data segment, constant data segment, and stack segment must be less than 64K bytes. In other words, all data in those three parts of the progratn be addressable as offsets from one segment register (normally DS).

This requirement exists because, in the medium model, these three segments are defined as a group. A group is simply a collection of segments that total less then 64K bytes in size. Grouping the segments allows all the data in them to be addressed as offsets frOln a single segment register.

In the medium model, the static data segment, the constant data segment, and the stack segment are defined as a group called DGroup. Hence the size restriction. Unless you program in assembly language, you don't need to define DGroup yourself - your compiler does it for you.

Why group segments? Why not address them each individually? The answer is speed. Loading a segment register takes time, so the less often a program has to load one, the faster it runs. This effect is especially great when a segment is referenced frequently during program execution, as the ones in DGroup are.

Figure 10-1 shows typical memory organization for a medium model program. The order of the data, constant, and stack segments within DGroup can vary. For details, see "Changing Memory Organization From the Default for Your Compiler," later in this section.

In real mode, code segments and the data/stack segments (DGroup) are loaded adjacent to each other in memory, with DGroup normally positioned at higher addresses than code. This organization matches the one shown in Figure 10-1.

Stack Format and Calling Conventions 10-3

High End of Partition Memory

Low End of Partition Memory

1---_ _ c_o_n_:_=_nC

t_k D_a_t_a_-i I'I(o-o-G-ro-u-p SP Static Data

'I( DS,SS

Code Segment Code Segment Code Segment Short-Lived

Memory

Long-Lived Memory

Figure 10-1. Typical Memory Organization in Medium Model Programs

In protected mode, however, code is loaded independently of data and may be located anywhere in memory. In protected mode, the program does not need to know where its code is physically located. The operating system manages all the addressing required.

The medium-model memory organization originated with the PL/M compiler, and most languages conform to it. See your programming language manual for more information.

10-4 eTaS/Open Programming Practices and Standards - Part II

Code Segments

Any number of separate code segments, each of which may contain up to 64K bytes, are addressed based on the CS (Code Segment) register. Only one code segment, the currently executing one, is addressable at a time.

The current code segment (and therefore the value in the CS register) changes with each far procedure call, far jump, or far return. All calls, jumps, and returns are far in the medium model, unless explicitly overridden. The IP (Instruction Pointer) register contains the offset of the next instruction to be executed.

Figure 10-1 shows DGroup positioned just above and adjacent to the program's code segments. This representation is typical in real mode. As mentioned earlier, in protected mode, code segments are loaded indepen-dently and may be located anywhere in memory.

Unallocated Memory

In real mode, a pool of unallocated memory is located below and immediately adjacent to the program, as shown in Figure 10-1. In protected mode, however, the memory pool is usually located just below and adjacent to DGroup, while the program's code may be anywhere, as was described earlier in this section. Short-lived memory is dynamically allocated toward lower addresses from the higher end of the memory pool.

Long-lived memory is allocated toward higher addresses from the lower end of the pool. (For details, see the discussion of memory management in your operating system manual.)

Notes on the Stack

Initially, the value in the SP (Stack Pointer) register is the highest address in the stack segment: the top of the stack. The value in SP decreases as the stack grows downward in memory.

Most compilers automatically provide more than enough stack space for their programs, but some programs may need to allocate extra space. This is more likely to be needed when a program performs many nested procedure calls (for example, if it uses recursion).

Stack Format and Calling Conventions 10-5

Caution: If the stack requirements of the program exceed what is allotted, the growing stack can ovenvrite program data, which may cause unpredictable results. If your program links successfully but malfunctions, and you suspect stack overflow, increase the stack size.

Values of OS and SS in Medium Model

In medium model, the DS (Data Segment) and SS (Stack Segment) registers have the same value. Both contain the selector that identifies DGroup.

In a program, the "objects" that you manipulate are usually static constants, static data variables, and the local variables on the stack. (See "Procedure Calls and the Stack," later in this section, for details on the stack format.) It is most efficient to address all three using the same segment selector.

As a simple example, assume that A is a static data variable, B is a local variable, and C is a constant in the following expression:

A=B+C

If all three objects can be addressed by the same segment selector, only the offset of each object is needed to do the calculations. If they cannot all be addressed by the same segment register, then the processor incurs more addressing overhead.

If DS and SS are equal, and an object on the stack (referenced from SS) is assigned to a static variable (referenced from DS), there is no segment register overhead required.

Caution: A common error in writing a mUltiprocessing program is to create a stack that jails to follow the convention of equating DS and SSe This error has no effect as long as you are fetching or storing the values of variables. However, it can cause invalid pointers to variables. Invalid pointers cause protection faults.

10-6 eTOS/ Open Programming Practices and Standards - Part II

Changing Memory Organization from the Default for Your Compiler High-level language compilers produce program modules in which the segment elements appear in a characteristic order by segment class (such as Code or Data). The Linker accepts the class order of the first object module it encounters as the order for the entire program.

Under some circumstances (for example, when using DS allocation, which is discussed next), you may need to change the order in which program segments are organized in memory. To do so, you must write an assembly language module that does nothing except declare segments in the order you want them. Then, list this template module first in your input to the Linker. (Such a template module may already be available with your language, under the file name of First.obj.)

The following is an example of such a template module:

stack segment word 'stack' stack ends

data segment 'data' data ends

const segment 'const' const ends

memory segment 'memory' memory ends

dgroup group stack,DATA,const,memory code segment 'code'

code ends end

Code Sharing

Most compilers emit code that supports the code-sharing feature of CTOS.

The only requirement for code sharing is that code be separate from data.

If this requirement is met, then multiple instances of the same program can share a single set of code segments. Each new instance of the program receives a new data segment, and selectors for the existing code segments.

Stack Format and Calling Conventions 10-7

Disposable Initialization Code

CTOS allows two class names for executable code segments: CODE and COED. Most programs use only CODE segments, which are normal, executable code segments. Some programs, however, need code which can be used once and then thrown away.

For example, a system service has no need to keep its installation code after it has installed itself. To conserve memory, a system service writer could put the installation code in a COED segment, then deallocate that segment after the service installs itself.

Creating a COED Module

If you program in Assembly language, creating a COED segment is easy.

Simply define a segment with class name COED and put your installation code in it. Then make that segment the first one in your program's memory image (in other words, at the lowest addresses in memory).

If you program in a high-level language, however, you need a utility to convert the class name in the object module your compiler emits. Most implementations of CTOS provide a utility that performs this function.

See your operating system documentation for more information.

To create a COED segment in a high-level language:

1. Create a small Assembly language template file that defines the COED segment as the first segment in the run file. See "Changing Memory Organization from the Default for Your Compiler" for details.

2. Put the disposable code in a separate source file from the rest of your code.

3. Compile that file to an object module.

4. Run the conversion utility on that object module.

5. Link the disposable code module with the rest of your program. Be sure to specify your segment template file as the first file on the Linker's input line.

10-8 eTOS/Open Programming Practices and Standards - Part II

The run file you create should now have a COED segment at the bottom of its memory image, which contains the disposable code.

Disposing of the Code in a COED Module

COED segments are treated as if they were dynamically allocated memory.

For this reason, the COED segment must be disposed of before the program allocates any dynamic memory.

After the program has executed the disposable code, it should release the COED segment that contains the code. To do so, the program can simply call DeallocMemorySL. For example, a COED segment that contains the procedure Initialize can be deallocated as follows:

pCOEDSeg

=

NULL;

selectorof(pCOEDSeg)

=

selectorof(Initialize);

CheckErc(DeallocMemorySL( pCOEDSeg, OxFFFF) );

The above code fragment first creates a pointer to the segment which contains the Initialize procedure (the COED segment), with an offset of

o.

Next, the fragment calls DeallocMemorySL with the pointer to the COED segment, and the hexadecimal value OxFFFF. These parameters tell the operating system to deallocate the entire segment.

Im Dokument Standards Programming (Seite 187-194)