Selecting and Accessing a Stack Segment

Introduction

A stack segment is a form of data segment. Its descriptor must identify it as a read/writable segment so that the processor may perform both pushes (i.e., writes to the stack) and pops (i.e., reads from the stack). The descriptor also describes the stack type. A stack may be designated as an expand-up stack (the most common type; described in “Accessing the Stack Segment” on page 76) or an expand-down stack. A description of the expand-down stack can be found in the section entitled “Expand-Down Stack” on page 164. It should be noted that most OSs implement expand-up stacks.

Expand-Up Stack

The discussion that follows describes the operation of an expand-up stack (see Figure 9-6 on page 167).

Figure 9-6. Expand Up Stack Approaching a Full Condition


Assume that the processor is in Protected Mode and the following series of instructions is executed:

mov   ax, 02ff               ;put 02ffh in ss
mov   ss, ax                 ;
mov   esp, 00005ffe          ;set stack pointer initial value
push  ebx                    ;save ebx in stack
mov   bx, [0100]             ;read value from memory to bx
add   cx, bx                 ;add bx to cx, result in cx
pop   ebx                    ;restore original value in ebx

The first two instructions set SS to 02FFh. This value is interpreted as illustrated in Figure 9-4 on page 163. The processor reads the segment descriptor from entry 95d in the LDT (TI bit = 1, indicating LDT, and the index field contains 95d), performs privilege checking and ensures that the descriptor defines a read/write data segment (W = 1). The example stack segment descriptor is illustrated in Figure 9-5 on page 164, and has the following characteristics:

  • The segment is a data or a stack segment (System bit = 1 and C/D = 0).

  • It can be read and written (W bit = 1).

  • The 32-bit ESP register (rather than the 16-bit SP register) is used to access it (B = 1).

  • It can be accessed by a program with any privilege level (DPL = 3).

  • The TOS (Top of Stack) equals the limit (07B3Eh, or 31550d).

  • It is an expand-up stack that grows downward from the (base + limit) towards its base address (E bit = 0).

  • Its base address is 00083EA0h.

Figure 9-4. Example Value in SS Register


Figure 9-5. Example Stack Segment Descriptor


This example assumed that the code segment's default operand size is 32-bits (in other words, the code segment descriptor's D bit = 1, indicating that this is 32-bit code). When this is the case, the 32-bit ESP register is decremented by four during the execution of a PUSH. When executing 16-bit code (D = 0), the 16-bit SP register is decremented by two.

When the PUSH instruction in the example code fragment is executed, the processor decrements SP by four and then writes the contents of the EBX register (four bytes) into memory. Before performing the write, the processor performs a limit check to ensure that the new ESP value (0005FFEh - 2 = 0005FFCh) doesn't exceed the size of the stack specified in the descriptor (5FFCh is < 7B3Eh). It also checks to ensure that decrementing ESP by four doesn't decrement ESP below 00000000h. If this were the case, a Stack Exception would be generated. The memory address is formed by adding the current contents of the ESP register (0005FFCh) to the segment's base address (00083EA0h), yielding memory address 00089E9Ch. The four bytes from EBX are written into memory locations 00089E9Ch through 00089E9Fh.

When the POP instruction in the code fragment is executed, the processor performs a four byte read from memory starting at the location currently pointed to by ESP + the stack segment's base address. The four bytes from memory locations 00089E9Ch through 00089E9Fh are read, with the byte from location 00089E9Ch (the lower location) placed in the LSB of EBX (BL) and the byte from location 00089E9Fh placed in its MSB. The processor then increments ESP by four.

Expand-Down Stack

The Problem

Assume that a programmer pushes a number of parameters onto the stack and that some of these values are pointers to other values that were pushed onto the stack. These pointers take the form of the offset from the BOS (bottom of stack).

For example, assume that the value 1234h is pushed into the stack at position (i.e., offset) 00003000h (ESP = 00003000h) and that the programmer later pushes a pointer to that value into stack position 00002FF0h. The value 1234h is stored in the stack at offset 00003000h, while stack location (offset) 00002FF0h contains the value 00003000h, the pointer to the value 1234h.

Now assume that the stack is approaching the full condition (in other words, it has almost been decremented down to its base address (Figure 9-6 on page 167).

To make the stack larger, the programmer copies the current stack onto the top of a larger stack segment (see Figure 9-9 on page 168). Any pointers stored in the stack (such as the one at offset 00002FF0h in the older, smaller stack) are now wrong (because the base address has been changed relative to where the pointer and the location it points to now reside). The value 1234h now resides at an offset other than 00003000h within the stack segment.

Figure 9-9. Copying to a Larger Stack Renders Stored Pointers Incorrect


In addition:

  • Enlarging the stack by lowering the base renders stored pointers incorrect. See Figure 9-7 on page 167.

    Figure 9-7. Enlarging the Stack by Lowering Stack Base Renders Stored Pointers Incorrect

  • Enlarging the stack by increasing the stack limit will not head off a stack overflow. See Figure 9-8 on page 168.

    Figure 9-8. Enlarging Stack by Increasing Limit Won't Head Off a Stack Overflow

The expand-down stack solves the problem.

Expand-Down Stack Description

Most OSs implement expand-up stacks (discussed earlier). However, a stack segment with E = 1 in its descriptor is defined as an expand-down stack. The author has always found this name to be misleading. As with an expand up stack, the stack still grows downward towards its floor as items are pushed into the stack. The only real difference is that the stack now has an artificial floor.

Refer to Figure 9-10 on page 169. An expand down stack is different from an expand up stack in the following ways:

  • The stack segment's base address specifies the real, ultimate floor of the stack.

  • Refer to Figure 9-11 on page 169. The limit specified in the stack segment descriptor no longer specifies the stack size. Rather, it specifies the artificial floor of the stack (i.e., the Bottom of Stack, or BOS). The artificial BOS = the actual stack segment base address + the limit + 1.

    Figure 9-11. Decreasing Limit Lowers the Stack's Artificial Floor

  • The offset of the Top of Stack (TOS) from the stack segment's actual base address is either FFFFh (if the B, or Big, bit in the stack segment descriptor = 0), or FFFFFFFFh (if the B, or Big, bit in the stack segment descriptor = 1).

Figure 9-10. Expand-Down Stack Approaching Full


An Example

As an example, assume that the stack segment is an expand-down stack, the segment's base address is 00000000h, its limit is FFFh, and that the B bit = 1 in its descriptor. This means that:

  • The stack segment's ultimate base address is 00000000h.

  • Its BOS is currently set to 00000000h + FFFh + 1 = 00001000h.

  • The offset of the TOS is FFFFFFFFh before anything is pushed onto the stack. The TOS of stack therefore = 00000000h + FFFFFFFF = FFFFFFFFh.

  • The first 32-bit object pushed into the stack is stored in locations FFFFFFFBh through FFFFFFFEh.

  • As additional items are pushed onto the stack, the stack grows downward towards its artificial floor (at location 00001000h).

  • If the stack is full and an attempt is made to push another item onto the stack, a stack exception is generated.

  • The OS's stack exception handler can adjust the artificial floor downwards towards it actual base address by decreasing the segment descriptor's limit value.

  • After doing so, the handler can return to and re-execute the PUSH instruction that caused the stack overflow exception. It will re-execute successfully because the artificial floor has been lowered.

Another Example

As another example, assume that the stack segment is an expand-down stack, the segment's base address is 02000000h, its limit is FFFh, and that the B bit = 1 in its descriptor. This means that:

  • The stack segment's ultimate base address is 02000000h.

  • Its BOS (i.e., its artificial floor) is currently set to 02000000h + FFFh + 1 = 02001000h.

  • The offset of the TOS is FFFFFFFFh before anything is pushed onto the stack. The TOS therefore = 02000000h + FFFFFFFF = 01FFFFFFh (notice that the result wraps around to lower memory).

  • The first 32-bit object pushed into the stack is stored in locations 01FFFFFBh through 01FFFFFEh.

  • As additional items are pushed onto the stack, the stack grows downward towards its artificial floor (at location 02001000h).

  • If the stack is full and an attempt is made to push another item onto the stack, a stack exception is generated.

  • The OS's stack exception handler can adjust the artificial floor downwards towards it actual base address by decreasing the segment descriptor's limit value.

  • After doing so, the handler can return to and re-execute the PUSH instruction that caused the stack overflow exception. It will re-execute successfully because the artificial floor has been lowered.

Stack Segment Privilege Check

The privilege check performed when a value is loaded into the SS register is the same as that performed for a data segment (see “Data Segment Privilege Check” on page 159).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.19.174