You must take special care when using the ES register in an assembly-language application. Under certain circumstances, a selector that points to a discarded data object in the ES register can cause your application to produce a general-protection (GP) fault. Also, a rare combination of circumstances can cause Windows to enter an infinite loop.
A GP fault occurs when a program pops the ES stack and the selector in the ES register refers to a segment that has been discarded. For example, in the following example, ES refers to a global memory object. Freeing the object invalidates the selector that was temporarily pushed onto the stack.
push es
.
.
.
cCall GlobalFree <es>
.
.
.
pop es
Your application need not discard a segment explicitly for it to be discarded. The following example shows how a segment can be discarded indirectly:
push es ; ES refers to a discardable data segment
.
.
.
call far Proc1 ; Proc1 directly or indirectly causes the memory
. ; object pointed to by ES to be discarded
.
.
pop es
Windows handles code-segment faults. It does not handle data-segment faults, however, so this example would result in a GP fault.
An unusual situation can arise that puts Windows in an infinite loop when the ES register holds the selector to a discardable code segment. In such cases, you should clear ES before making a call from one discardable segment to another. The following example shows how to make such a call:
mov es, _CODESEG1 ; CODESEG1 is discardable
.
.
.
xor ax, ax ; This sample clears the ES register before
mov es, ax ; calling from a discardable segment to a
call far Proc1 ; discardable segment
If you fail to clear the ES register in this situation, the Windows segment fault handler can enter an infinite loop, discarding and reloading the three discardable code segments when memory is low. During this process, the ES stack is pushed and popped, forcing CODESEG1 to be unnecessarily reloaded when the “code fence” has room only for the other two segments.