X86 assembly programming in protected mode

From Free net encyclopedia

Revision as of 02:19, 29 March 2006; view current revision
←Older revision | Newer revision→

Template:Lowercase Template:Wikibookspar

The most frequently used x86 assembly language is x86 assembly programming in protected mode. x86 assembly programming in protected mode utilises 32-bit or 24/16-bit addressing of registers and memory, and enables other features such as protection and paging, which is new to 386. Protected mode is the mode in which most modern operating systems run their code. When the computer boots, it first enters real mode; the operating system is responsible for switching into protected mode.

Contents

Application registers

In protected mode, there are 8 32-bit or 16-bit general-purpose registers for use:

  • data registers
    • EAX or AX, the accumulator
    • EBX or BX, the base register
    • ECX or CX, the counter register
    • EDX or DX, the data register
  • address registers
    • ESI or SI, the source register
    • EDI or DI, the destination register
    • ESP or SP, the stack pointer register
    • EBP or BP, the stack base pointer register

In addition there are non-application registers available, which change the state of the processor:

  • control registers
    • CR0 or MSW
    • CR1
    • CR2
    • CR3
    • CR4
  • debug registers
    • DR0
    • DR1
    • DR2
    • DR3
    • DR6
    • DR7
  • test registers
    • TR4
    • TR5
    • TR6
    • TR7
  • descriptor registers
    • GDTR, the global descriptor table register (see below)
    • LDTR, the local descriptor table register (see below)
    • IDTR, the interrupt descriptor table register (see below)
  • task register
    • TR

All of them can be used both for segmented addressing of memory and for holding data. Some of these registers are however better to use for certain operations than others. This is because mnemonics using certain registers could be translated into shorter opcodes than if they used other registers.

The lower 16 bits of each 32 bit register can be addressed separately and like a register in its own right, and the low 16 bits of the first four registers (EAX, EBX, ECX, EDX) can be further broken up into two eight-bit registers. The 16 bits of data in these first four 16 bit registers can be addressed 8 bits at a time: the upper eight and the lower eight bits, and can be treated as registers in their own right.

If we take the EAX register, this register contains 32 bits and the lower 16 bits can be addressed by the AX register. The upper 8 bits of the AX register can be addressed by the AH register and the lower 8 bits of the AX register can be addressed by the AL register.

For example, if ECX initially contains the number 0x3A3F901D and CH changes to 0x44, then ECX will also change to contain 0x3A3F441D.

There is also a 32-bit or 16-bit wide flags register, named EFLAGS or FLAGS, which contain the processor state. Each flag is one bit - and thus set 0 or 1, also called set, high, and unset or low. Important flags in the EFLAGS or FLAGS register is: carry (bit 0), zero (bit 6), sign flag (bit 7) and overflow (bit 11).

Flags are notably used in the x86 architecture for comparisons. A comparison is made between two registers, for example, and in comparison of their difference a flag is raised. A jump instruction then checks the respective flag and jumps if the flag has been raised: for example

    cmp eax, ebx
    jne do_something

first compares the EAX and EBX registers, and if they are unequal, the code branches off to the do_something label.

There is also a 32-bit or 16-bit instruction pointer, named EIP or IP. The EIP or IP register points to where in the program the processor is currently executing its code. The EIP or IP register cannot be accessed by the programmer directly. Instead, a sequence like the following can be done to retrieve the address of next_line into EAX:

    call next_line
next_line:
    pop eax

This works even in position-independent code because call takes an EIP or IP-relative immediate operand. To write to EIP or IP is simple:

    jmp eax

Mnemonics for opcodes

In protected mode, the following mnemonics are available: aaa, aad, aam, aas, adc, add, and, arpl, bound, bsp, bsr, bt, btc, btr, bts, call, cbw, cwde, clc, cld, cli, clts, cmc, cmp, cmps, cmpsb, cmpsw, cmpsd, cwd, cdq, daa, das, dec, div, enter, hlt, idiv, imul, in, inc, ins, insb, insw, insd, int, into, iret, iretd, ja, jae, jb, jbe, jc, jcxz, jecxz, je, jz, jg, jge, jl, jle, jmp, jna, jnae, jnb, jnbe, jnc, jne, jng, jnge, jnl, jnle, jno, jnp, jns, jnz, jo, jp, jpe, jpo, js, jz, lahf, lar, lea, leave, lgdt, lidt, lgs, lss, lds, les, lfs, lldt, lmsw, lock, lods, lodsb, lodsw, lodsd, loop, loope, loopz, loopne, loopnz, lsl, ltr, mov, movsx, movzx, mul, neg, nop, not, or, out, outs, outsb, outsw, outsd, pop, popa, popad, popf, popfd, push, pusha, pushad, pushf, pushfd, rcl, rcr, rol, ror, rep, repe, repz, repne, repnz, ret, sahf, sal, sar, shl, shr, sbb, scas, scasb, scasw, scasd, seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae, setnb, setnbe, setnc, setne, netng, setnl, setnle, setno, setnp, setpe, setpo, sets, setz, sgtd, sidt, shld, shrd, sldt, smsw, stc, std, sti, stos, stosb, stosw, stosd, str, sub, test, verr, verw, wait, xchg, xlat, xlatb, xor.

(not including the floating point, SIMD and some other instructions)

There are also some undocumented instructions, like the umov instruction that could be used for in circuit emulators. (umov stands for "user move", and with the knowledge of that instruction it becomes much easier to write certain types of software debuggers.)

The addressing model in protected mode

It is important to differ addresses from each other in protected mode. There are physical addresses, linear addresses and logic addresses.

A logic address is a segment-register and an offset-register paired together. With other words: A logic address is a pointer inside a program.

A linear address is a logic address that has gone through the descriptor-mechanism. (see Descriptors below.)

A physical address is a logic address that has gone through the paging mechanism. (see Paging below.)

That means that inside protected mode with paging, each address has to go through two layers of redirectioning before it gets through to the real memory.

Descriptors

There is a Global Descriptor Table (GDT) and a Local Descriptor Table (LDT) that holds information about how the memory should look and behave. The GDT is pointed to by the GDT register (GDTR) and the LDT is pointed to by the LDT register (LDTR). The pointers to these tables are 48 or 40 bits wide, and contain two fields: A pointer to the beginning of the table (base), and a part that describes how large the table is in bytes (limit).

The base can be either 24-bits or 32-bits wide.

To address some point in the memory, a segment register and an offset register are used. Segment registers are:

CS, DS, ES, FS, GS and SS.

CS points to the segment containing code and DS to the data segment. ES, FS and GS point to extra segments that could be used to store additional data. The SS segment is used to hold the stack.

Each segment register points to a descriptor. Each descriptor points to a well-defined data area. If the descriptor that GS points to defines its data area to start at 0x000A0010, and to end at 0x000C0000, and the EAX register contains the value 0x0001C234, then the combination GS:EAX will point to 0x000BC244.

The GDT and LDT contains descriptors that point to data areas that have different properties. Most often, there is one null descriptor, 2 data descriptors, 2 code descriptors, and multiple TSS descriptors. Most often, the code and data descriptors point to an area in memory that starts at 0 and ends at 4 gigabytes. This way, descriptors and segment registers become almost invisible for the application programmer. This is called the flat memory model. In flat memory, segment registers lose their importance. Only offset registers are used to indicate addresses.

TSS descriptors are used to hold information about tasks. TSS descriptors are part of the hardware support for context switching provided by x86 processors.

If a segment register points to a descriptor in the GDT or LDT that has a 32-bit base while switching back to realmode, the segment register will continue to point to the 32-bit descriptor for as long as it stays unmodified. If the descriptor has a base pointing to 0, a limit of 4 gigabytes, and the D-flag set, then it will become possible to use 32-bit addressing in realmode. This is sometimes called unreal mode as this is not entirely ordinary realmode behaviour.

Pages

On 386s and later paging can be turned on and off with the help of bit 31 in the CR0-register. Register CR3 is used to point to the page directory table. See paging.

Memory layout for PCs in protected mode

The memory layout for computers in protected mode is similar to that of real mode. Alas, some PCs have the 15th megabyte occupied by the video-card.

  0-3FF        Interrupt Handler/Application RAM
  400-5FF      BDA (BIOS Data Area) *
  600-9FFFF    Application RAM
  A0000-BFFFF  VGA Video memory
  C0000-EFFFF  Optional ROMs (The VGA ROM is usually located at C0000)
  F0000-FFFFF  BIOS ROM
* = The BIOS is inactive in protected mode, therefore this area could be
considered to be "application RAM" as well.

Supervisor mode

See supervisor mode

Interrupts in protected mode

Interrupts are the same as in realmode, except they can perform more complicated switches. For example, an interrupt in protected mode can be programmed to automatically switch into a specific process or thread.

The Interrupt Description Table (IDT) is pointed by the IDT-register (IDTR), which is 40-bits or 48 bits wide and works just like the GDTR/LDTR. (See above.)

How to switch to protected mode

  • load GDTR with the pointer to the GDT-table.
  • disable interrupts ("cli")
  • load IDTR with the pointer to the IDT
  • set the PE-bit in the CR0 or MSW register.
  • make a far jump to the code to flush the PIQ.
  • initialize TR with the selector of a valid TSS.
  • optional: load LDTR with the pointer to the LDT-table.

See also