• Keine Ergebnisse gefunden

Real Mode versus Protected Mode Pointers

Im Dokument Standards Programming (Seite 89-100)

As discussed above, a pointer consists of a segment address (SA) and an offset (RA), and references a particular location in a program's memory space. The offset portion of a pointer is always the count of bytes from the beginning of the segment to the location referenced. The segment address, though, has different meanings in real mode and in protected mode.

In real mode, a segment address (SA) refers to a physical location in memory. Every sixteenth byte in memory has a segment address assigned to it. The segment address times 16 equals the physical address of that byte. For this reason, real mode segment addresses are sometimes referred to as paragraph numbers (16 bytes equals one paragraph in the Intel architecture).

5 - 2 eTOS/ Open Programming Practices and Standards - Part I

In protected mode, a segment address refers only to an entry in a descriptor table maintained by the processor. The processor uses the segment address as a key to look up a physical memory address in the descriptor table. Because of this, there is no direct relation between the segment address and any location in physical memory. Protected mode segment addresses are sometimes referred to as selectors, to emphasize their function as a table lookup index.

In real mode, pointer arithmetic can be performed, because any pointer refers directly to some location in physical memory. In protected mode, however, no pointer ever refers to a location in physical memory. Instead, pointers refer to an index in a descriptor table, and to the offset from whatever location that index points to. Segment arithmetic or direct comparison of pointers is meaningless in protected mode, because any index in a descriptor table can point to any location in memory.

General Programming Guidelines

GUIDELINE: Do not use segment address arithmetic.

Compatible programs cannot add or subtract segment addresses to produce new segment addresses, because segment address arithmetic does not work in protected mode. (For reasons, see "Real Mode Versus Protected Mode Pointers," earlier in this section.)

GUIDELINE: Use FComparePointer to compare pointers.

Because multiple selectors may refer to the same physical memory location, protected mode programs cannot depend on the binary comparison of pointer values to test for pointer equality. (Pointers are equal if they reference the same byte location).

Compatible programs should use FComparePointer with a case value of 1 to test for pointer equality.

Protected Mode Programming Guidelines 5-3

Example:

/* Compare the pointer equality of a response pointer */

/* to a request block pointer.*/

Pointer pRqReti Word Rqi

CheckErc(Wait(exch, &pRqRet»i

if( FComparePointer(pRqRet, &Rq, 1)

==

TRUE) [

/* The pointers are equal (that is, they reference */

/* the same byte location).*/i )

Listing 5-1. Comparing Pointer Equality

GUIDELINE: For contiguous data objects larger than 64K bytes, use multiple segments.

A real mode program can make a single call to AllocAllMemorySL to allocate a large data object (more than 64K bytes), then address the data using segment address arithmetic. This technique fails in protected mode.

(See "Real Mode Versus Protected Mode Pointers," earlier in this section for details ~)

The recommended method for compatible programs is to make multiple calls to AllocMemorySL. This will decompose the large data object into multiple segments, each of which is then addressable by a returned pointer. The memory allocated by multiple calls to AllocMemorySL is contiguous.

GUIDELINE: Use compatible memory management operations.

Several memory management operations have been specifically designed for use by compatible programs. These are

AllocAreaSL ExpandAreaLL ExpandAreaSL ShrinkAreaLL ShrinkAreaSL

5-4 eTOS/Open Programming Practices and Standards - Part I

These memory operations manage memory allocation and deallocation within a single segment. For more information about these operations, see Chapter 16, "Memory Management" in Part II of this manual, or see the eTaS/Open Application Programming Interface Specification.

Compatible programs that depend on detecting contiguity between separately allocated chunks of memory should use these operations. They provide up to 64K bytes of contiguous memory. A program can test for contiguity within a segment by comparing pointer offsets (RAs).

Compatible programs should use ExpandAreaSL instead of AllocMemorySL if they make multiple calls to allocate small, fixed-length segments. This is because, in protected mode, each call to AllocMemorySL allocates a new selector, while ExpandAreaSL does not.

GUIDELINE: Use ExpandAreaSL to allocate DS-relative memory.

The Linker's data segment (DS) allocation option enables run time expansion of a program's static data area. The Linker assigns static data addresses at the high-order end of the data segment's 64K-byte range, leaving address space below for expansion.

DS allocation requires that static data be located at the low-order end of the program image. For more information about DS allocation, see Chapter 10, "Stack Format and Calling Conventions," and Chapter 16,

"Memory Management" in Part II of this manual.

Compatible programs should use ExpandAreaSL instead of AllocMemorySL to dynamically expand the data segment. Programs that use AllocMemorySL will not work in protected mode because, instead of expanding the existing data segment, each call to AllocMemorySL allocates a new selector for a new segment.

GUIDELINE: Do not use the memory array option.

The Linker's memory array option directs the operating system to allocate additional memory at the end of a program's static data. If a program needs additional memory relative to its static data segment, it should use the DS Allocation option described above.

Protected Mode Programming Guidelines 5-5

GUIDELINE: Do not use segment registers to store data.

In real mode, segment registers can be used to store data with no adverse consequences.

In protected mode, however, loading a segment register with a value that is not a valid selector will cause a protection fault, which is a fatal event in a program.

Compatible programs should use segment registers only for valid segment addresses.

GUIDELINE: Use proper NIL pointers.

A NIL pointer, also called a NULL pointer, is a pointer that has a segment address of zero.

Historically, when a pb/cb (pointer/length) pair was used, a cb of zero was often used to indicate a NIL pointer. This convention does not work in protected mode, because the arbitrary data in the uninitialized pb (pointer) may be loaded into a segment register before the length is checked. If this happens, it causes a protection fault.

Compatible programs should always initialize NIL pointers to zero.

Example:

Pointer Word Pointer

pReti cbReti Pi

/* Call the InitPbCb procedure (defined later) to set */

/* the pointer to NULL.*/

InitPbCb(&pRet, &cbRet)i

/* Use of a NIL pointer prevents a general protection */

/* (GP) fault if pRet is copied.*/

p

=

pReti }

continued ...

5-6 eTaS/Open Programming Practices and Standards - Part I

/* Use a procedure (InitPbCb, in this example) to set */

/* the pb/cb to zero.*/

void InitPbCb(Pointer ppRet, Pointer pCbRet) (

*ppRet = 0;

*pCbRet = 0;

)

GUIDELINE:

Listing 5-2. Initializing Pointers

Code segments should have CODE or COED for the name of the segment class.

In protected mode, the contents of a segment are executable as code only if the segment is typed as a code segment.

Compatible programs should use the class name CODE or COED for code segments. Most compilers use the CODE class name for code segments, though there are special cases. The COED class name is created by the Coed source build utility and is used to designate initialization code that is deallocated after use.

Make sure that code segments defined in assembly language programs have the class name CODE or COED.

Example:

;declare a code segment with name "myCode" and class

; "CODE"

myCode segment 'CODE'

myCode ends

GUIDELINE: COED Segments

COED segments can be deallocated after the initialization code in them has been used. COED segments are simply code segments having the class name COED. This class name is created by the Coed source build utility.

Protected Mode Programming Guidelines 5-7

COED segments must be located at the beginning of the run file image, immediately before static data. A program normally deallocates its COED segments using the DeallocMemorySL operation.

In real mode, the size of the memory deallocation is computed using segment address arithmetic. This does not work in protected mode.

Compatible programs using COED segments should use different deallocation schemes in real and protected mode. Deallocation should be based on a run time check of the execution mode using the FProtectedMode operation.

In protected mode, deallocate the COED segments by calling DeallocMemorySL for each COED segment using the following parameters:

pSegment cBytes

Is SN :RA, where SN is the COED segment selector, and RA is 0.

Is OFFFFh, meaning deallocate the entire segment.

The usual stack discipline rules apply to DeallocMemorySL. COED segment deallocation must occur before the program's first call to AllocMemorySL or AllocAreaSL. COED segments must be deallocated in the order of first defined (in other words, located lowest in the program's memory image), first deallocated.

For more information about disposable code, see Chapter 10, "Stack Format and Calling Conventions" in Part II of this manual.

GUIDELINE: Writable code segments are not permitted.

In protected mode, nothing can be written to a segment that is defined as a code segment. Therefore, compatible programs cannot have writable variables in the code segment, nor can they contain self-modifying code.

If you need to write to an executable segment, or need to make a writable segment executable, you must first create an alias for the existing segment.

Then, you can use the SetSegmentAccess operation to change the segment type so that it may be written (or executed).

The following example creates an alias for the program's data segment. It then sets changes the segment type to CODE. If the array in the example 5-8 eTOS/Open Programming Practices and Standards - Part I

contained machine-language instructions instead of characters, they could be executed. Instead, the example just prints the array to verify that the alias is valid, then compares the original and alias pointers.

Example:

"\nAlias Code Pointer and Data Pointer reference different locations";

CheckErc (CreateAlias (pData, &sgCode»;

CheckErc (SetSegmentAccess (sgCode, 10»;

/* now construct a pointer to our code and print the */

Protected Mode Programming Guidelines 5-9

/* finally compare data pointer and code pointer */

pData

=

&pTestMsg;

if (FComparePointer (pData, u.ptr, 1) != FALSE) printf (pSameMsg);

else

printf (pDiffMsg);

ErrorExit (0);

}

Listing 5-3. Creating a Pointer Alias

GUIDELINE: Avoid timing loops.

Compatible programs should not contain timing loops or busy wait loops that depend on instruction execution speed. Use the Delay operation when the delay time is at least 100 milliseconds. Use the ShortDelay operation when the amount of time is less then 100 milliseconds.

Example:

/* delay 0.5 sec */

CheckErc(Delay(S»;

GUIDELINE: Use only compatible instructions.

The 80186 and 80286 microprocessors provide extensions to the 8086 microprocessor instruction set. Similarly, the 80386 provides additional extensions.

A compatible program should use the instruction set of the least capable machine on which it is to run.

If a program needs to run on 80186-based computers, as well as 80286 and 80386 computers, do not use the PUSH SP instruction. When it executes that instruction, the 80186 pushes a different value than the 80286 and 80386 do.

5-10 eTaS/Open Programming Practices and Standards - Part I

Language-Specific Guidelines

GUIDELINE: NIL pointer problems may occur as a result of certain coding sequences.

In protected mode, it is valid to put 0 in a segment register, but not valid to use it to address data. A segment register with 0 in it is "out of action"

temporarily. Of course, attempting to reference data at paragraph number 0 in real mode is usually an error as well, at least in a user program.

Constructs such as the following PL/M example, however, may be valid in real mode but cause a protection fault in protected mode, due to the kind of code generated by the compiler.

Example:

declare pFoo

declare foo based pFoo

pointer;

word;

if (pFoo

<>

0) AND (foo = 1) then do;

end;

In PL/M, the preceding construct gives the compile'r permission to test pFoo and foo in either order. Access to foo, however, must NEVER take place if pFoo is NIL, or a general protection fault will occur. To avoid this fault, the preceding code should be rewritten as follows:

declare pFoo

declare foo based pFoo

pointer;

word;

if pFoo

<>

0 then IF foo = 1 then

do;

end;

Protected Mode Programming Guidelines 5-11

GUIDELINE: Check the Execution mode.

A compatible program may have good reason to use different algorithms in real and protected modes. Such programs may still be packaged as a single run file by including both algorithms with run time checks in the code to choose between them.

Compatible programs should use the FProtectedMode operation to determine their execution mode.

Example:

if( FProtectedMode() != FALSE) [

/*Use a protected mode algorithm.*/i

}

else [

/*Use a real mode algorithm.*/i

}

Real Mode Guidelines

GUIDELINE: Use only those procedures that are available to real mode programs.

Certain operations (such as SgFromSa) are available only in protected mode. These operations are generally not useful to real mode applications and are therefore not available to them. If a real mode program attempts to use one of these procedures, the program will either fail to link or it will encounter an error at run time.

5 -12 eTOS/ Open Programming Practices and Standards - Part I

6

Im Dokument Standards Programming (Seite 89-100)