Protected mode programming

DLLs and EXEs generated by the PowerBASIC 32-bit compilers require Microsoft Windows 95 or later, or Windows NT 3.10 or later.  This includes Windows 98, Windows ME, Windows NT 4.0, Windows 2000, Windows XP, Windows Vista, and so on.  All of these operating systems run your program in protected mode, using a 32-bit flat memory model.

In real-mode operating systems such as DOS, it was possible to overwrite sections of the operating system code if a program was not correctly written.  This would crash the operating system and the computer would require a reboot before it would run again.

Protected-mode memory is designed to prevent this from happening.  It uses a protected mode memory manager to control the address range that all applications can read and write to, and the memory manager terminates any application that tries to read or write to a memory address range that is outside of the allocated application memory space.  The memory region assigned to an application is known as the process address space.

This style of memory management was available in 16-bit Windows but because of the method that 16-bit Windows used to simulate multitasking, it was possible to overwrite sections of memory that were owned by other applications or the operating system before the errant program crashed.

Depending on what portions of the operating system were overwritten, another (completely unrelated) program that had no errors in it could try to use a damaged operating system function, resulting in both a program and operating system crash.

The common symptom of this behavior was the infamous "blue screen of death" which told you something was wrong, but often reported misleading causes of the problem.  If an application destroyed critical sections of the operating system, the result was often a "black screen of death" - an instant black screen accompanied by a solidly locked or frozen machine.  This obviously gave no feedback as to the cause of the problem.

As improvements in hardware design occurred, the use of hardware based multitasking in 32-bit Windows made protected-mode memory managers increasingly reliable and resulted in new operating systems with ever increasing stability - more able to cope with preventing operating system crashes when an application crashes.

From this we can see that one of the fundamental "rules" of writing code for a protected mode operating system is to ensure the application code can read and write only within the process address space.

However, because Inline Assembler allows you to read and write to almost any memory address, this clearly places the onus on the programmer to take suitable precautions with all referenced memory addresses.

For example, if you allocate a 10 Kb buffer and subsequently try to read 20 Kb, the protected mode memory manager will trigger a Page Read fault (GPF) the instant the address goes outside the process address space - typically this would occur when the memory address advances beyond the original 10 Kb buffer.

An application can also get into similar trouble if it incorrectly dereferences a register (i.e., if it incorrectly treats the register content as a pointer or address, rather than a value).  If the address points outside of the allocated process address space, a GPF is virtually guaranteed.

Page read and write faults are exceptions (GPFs) that are passed from the operating system to the application that makes the error.  If the exception is not handled by the application, the operating system closes the application.  Current versions of PowerBASIC do not support native exception handling, but it is possible to configure an exception "trap" function using the Windows API.

Therefore, to create effective and stable assembler code, you should become familiar with protected mode programming concepts.  As outlined above, you must never access memory not specifically assigned to your process, nor should you ever change the selector value in a segment register.

Likewise, all Calls, Jumps, and Returns should use "Near" addressing, as a full 32-bit offset is utilized.  Should you violate any of the rules of protected mode programming, your code will likely fail catastrophically with a General Protection Fault (GPF).

 

See Also

The Inline Assembler

Flat memory model