Memory protection (i)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 18

Source: Internet
Author: User

This article is the 12th chapter of the original book study notes.

Say a digression, this post is to write, because let me mistakenly deleted, abominable is csdn in the Recycle Bin can not find! Well, then write it again, I have a strong will. Sima Qian said: "The King detained and played the book of Zhouyi," Donnieu and the "Spring and Autumn", Qu Yuan exile, is Fu "Li Sao", Zho Chu blindness, there is "Mandarin", grandson patella feet, "Art of War" fixed, not Weichan Shu, musicians "Lu" ... "Well, not sensational, get to the point."

The code for the 12th chapter is as follows.

1; listing 12-12; filename: c12_mbr.asm3; File Description: Hard disk main boot Sector code 4; Date Created: 2011-10-27 22:5,256; set stack segments and stacks Pointer 7 mov eax,cs 8 mov ss,eax9 mov sp,0x7c0010 11; Calculate the logical segment of the GDT address of the other MOV ea X,[CS:PGDT+0X7C00+0X02];         32-bit linear base address of GDT edx,edx14 mov ebx,1615 div ebx; decomposed into 16-bit logical address 1617         mov ds,eax; make DS point to this segment for operation of MOV ebx,edx; Start offset in paragraph address 1920         Create the 0# descriptor, which is the null descriptor, which is the processor's requirement for the MOV DWORD [ebx+0x00],0x0000000022 mov DWORD [ebx+0x04],0x00000000 2324 Create a # descriptor, which is a data segment that corresponds to the linear address space of 0~4GB for the Mov DWORD [ebx+0x08],0x0000ffff; The base address is 0, the segment bounds is 0XFFFFF26 mov dword [ebx+ 0x0c],0x00cf9200; granularity 4KB, memory segment descriptor 2728; Create protected Mode initial code snippet descriptor in MOV DWORD [ebx+0x10],0x7c0001ff; base address is 0x0000 7c00,512 byte of the Mov DWORD [ebx+0x14],0x00409800; granularity is 1 bytes, code snippet descriptor 3132; Create alias descriptor for the above snippet X mov DWord [ebx+0x18],0x7c0001ff; base address is 0x00007c00,512 byte. mov DWORD [ebx+0x1c],0x00409200; granularity is 1 bytes, data segment Descriptor 3536         MOV DWORD [ebx+0x20],0x7c00fffe37 mov DWORD [ebx+0x24],0x00cf960038 39; Initialize Descriptor Descriptor Register GDTR40                         mov word [cs:pgdt+0x7c00],39; the bounds of the descriptor Lgdt [cs:pgdt+0x7c00]43] in al,0x92                                ; The port in the South Bridge chip is al,0000_0010b46 out 0x92,al; open A204748 CLI                        Interrupt mechanism has not yet worked 4950 mov eax,cr051 or eax,152 mov cr0,eax ; set PE bit 53 54; The following enters the protection mode ... JMP DWORD 0x0010:flush; 16-bit Descriptor Selector Sub: 32-bit offset 56 57 [                      bits [] flush:59 mov eax,0x0018 DS,EAX61 mov mov eax,0x0008; load data Segment (0..4GB) Select SubES,EAX64 mov mov fs,eax65 mov gs,eax66, mov eax,0x0020; 0000 0000 0010 000068 mov ss,eax69 xor esp,esp; ESP <-070 * mov DWORD [es:0x0b8000],0x072e0750; character ' P ', '. ' And its display properties of the ES:0X0B8004],0X072E074D mov DWORD [the character ' M ', '. ' And its display properties of the X-mov DWORD [es:0x0b8008],0x07200720; two whitespace characters and their display properties.                           Its display property is 7576; start bubbling sort of ecx,pgdt-string-1 mov; traversal count = string Length-1 @@1:79 push ECX                                      ; the loop in 32-bit mode uses ECX-n xor bx,bx, and in 32-bit mode, the offset can be 16 bits or 81 @@2: ; is the back of the 32-bit AX,[STRING+BX mov] ah,al cmp; Ah is stored in the source word High byte jge @@3 xchg Al,ah [String+bx],ax] @@3:88 Inc BX Loop @@2 9 0 pop ecx @@192 Loop 93        mov ecx,pgdt-string94 xor ebx,ebx; offset address is 32 bit case 95 @@4:          32-bit offset with greater flexibility in ah,0x0797 mov al,[string+ebx]98 mov [es:0xb80a0+ebx*2],ax ; demonstrates 0~4GB addressing. ebx100 Loop @@4101 102 hlt 103104;---------------------------------------------------- ----------------------------A-string db ' s0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw. '                      106;-------------------------------------------------------------------------------107 PGDT DW 0108 DD 0x00007e00; The physical address of the GDT 109;-------------------------------------------------------------------------------11 0 times 510-($-$$) DB 0111 db 0X55,0XAA
1. Set stack segments and stack pointers
6         . Set stack segment and stack pointer 7         mov eax,cs      8         mov ss,eax9         mov sp,0x7c00

7th, 82 lines, you may feel a bit strange, but it is OK to write. For reasons, the author has already explained in the book.

[Bits 16]mov ds,ax        ; 8E d8[bits 32]mov ds,ax        ; 8E D8mov ds,eax       ; 8E D8

The comments on each line of the above code are the machine code generated after the instruction is compiled.

For some older compilers, the 16-bit and 32-bit compilation results are different when compiling the "MOV ds,ax" directive: in 32-bit mode, the prefix 0x66 is added (because the compiler considers the source operand ax to be 16-bit, so add 0x66 to reverse the size of the default operand).

However, if 0x66 is added, the processor will spend more time on the clock during execution, so the instructions are used very frequently, so whether it is a 16-bit or 32-bit pattern, they are designed to be the same machine instruction, all 8ed8, and no instruction prefix is required. But some compilers are too stubborn, and they still add the instruction prefix 0x66. Well, in order to take care of them, the programmer came up with a way to use this form:

MOV ds,eax

You don't say that, it really works, and sure enough, the 8ed8! is generated without a prefix.

Speaking of which, the NASM compiler is still very good, at least he will not be so stubborn. Regardless of how the processor pattern changes, and regardless of the form of the instruction, the following code compiles a result:

[Bits 16]mov ds,ax       ; 8E D8mov ds,eax      ; 8E d8[bits 32]mov ds,ax        ; 8E D8mov ds,eax       ; 8E D8

Said so much, in fact, I am the author of the content of the story again. Whether you understand it or not, I'm a little confused anyway.

Since the first code is executed in 16-bit mode, the compilation is compiled according to the 16-bit, so the 16-bit notation is possible. The following is a simple and straightforward way to write.

7         mov ax,cs      8         mov ss,ax

After disassembly, the generated machine code is as follows:

However, if you follow the book procedure, then the disassembly becomes:

See, the first line is more than the prefix 0x66, the execution will be more use of a period of instruction.

I personally think that writing code in a popular way, can make people understand the code is good code. OK, this is the problem here, we continue.

2. Create GDT
         calculate the logical segment address of the GDT.         mov eax,[cs:pgdt+0x7c00+0x02]      ; The GDT's 32-bit linear base addresses the         xor edx,edx14         mov ebx,1615         div ebx                            , decomposed into 16-bit logical addresses 1617         mov ds,eax                         ; Enable DS to point to the segment for Operation         . mov ebx,edx                        ; start offset address in segment
106;-------------------------------------------------------------------------------107     PGDT             DW 0108                      DD 0x00007e00      ; The physical address of the GDT 109;-------------------------------------------------------------------------------

The 12th line, is to the GDT's physical address 0x7e00 to eax, as to why the label Pgdt Plus (0x7c00+0x02), I believe you have understood, if not understand, look at my figure.

Line 13th to 15, in fact, is to do division operations, the physical address decomposition into a segment address and offset address: EDX:EAX/16 = EAX (get segment address) ... EDX (get offset address)

On line 17th to 18th, ds:ebx points to the beginning of the GDT.

         Create a 0# descriptor, which is an empty descriptor, which is the processor's requirement for the         mov DWORD [ebx+0x00],0x0000000022         mov DWORD [ebx+0x04],0x00000000  2324         ; Create a # descriptor, which is a data segment that corresponds to the 0~4GB linear address space of the         mov DWORD [ebx+0x08],0x0000ffff    ; the base address is 0 and the segment bounds is 0xfffff26         mov DWORD [ebx+0x0c],0x00cf9200    ; granularity is 4KB, memory segment descriptor 2728         ; Create a/* descriptor, Protected mode initial code snippet descriptor in         mov DWORD [ebx+0x10], 0X7C0001FF    ; The base address is 0x00007c00,512 byte         , the Mov DWORD [ebx+0x14],0x00409800    ; granularity is 1 bytes, code snippet descriptor 3132         ; Create 3# Descriptor, the alias descriptor of the preceding code snippet is the         ebx+0x18],0x7c0001ff of MOV DWORD [    ebx+0x1c], the base address is 0x00007c00,512 bytes of the "         mov" DWORD 0x00409200    ; granularity is 1 bytes, data segment Descriptor

The 20th to 30th Line created 3 descriptors, and I'm sure everyone is familiar with it. What needs to be explained is the 33~34 line, which creates an alias descriptor for a code snippet. What is the purpose of this?

In protected mode, the code snippet is not writable, so-called non-writable does not mean that the physical nature of the memory changed, so that the memory is not written, but that the code snippet descriptor access to the corresponding memory area, the processor does not allow to write data or change data.

However, if you want to modify the code snippet, is there a way? Yes, that is to create a new descriptor for the code snippet, such as a readable writable data segment descriptor, so that we can modify the code snippet in an overt manner with this data segment descriptor. Like this, when two or more descriptors point to the same segment, the additional descriptors become alias descriptors.

3. Protection during stack operation
$         mov DWORD [ebx+0x20],0x7c00fffe37         mov DWORD [ebx+0x24],0x00cf9600

The 36th, 37 line installs the stack segment descriptor. Analyze it with our applet (see Data Segment Descriptor and code snippet Descriptor (ii)-"X86 assembly language: From the actual mode to the protected mode" Reading note 11), the result is:

-----------------------
Seg_base = 0x7c00
Seg_limit = 0XFFFFE
S = 1
DPL = 0
G = 1
d/b = 1
TYPE = 6
Data segment: Scale down, readable and writable
------------------------
learned that the base address is 0x7c00, the threshold value in the descriptor is 0xffffe,g=1, which is the read-write data segment (generally as a stack) that extends down.

Effective limit (effective limit)

The effective bounds of the segment depend on the G flag.

G=0: The effective limit is the limit value in the descriptor

G=1: Effective bounds = segment bounds value in Descriptor * 0x1000 + 0xFFF

Keep this concept in mind, as we will use it many times.

For the e=1 data segment, the valid bounds specify the last offset address in the segment that is not allowed to be accessed.

B=0: The valid range of offset addresses is [effective bounds +1,0xffff], which is expressed in closed intervals for convenience of narration.

B=1: The valid range of offset addresses is [effective bounds +1,0xffff_ffff]

If you want to access a stack segment that is scaled down, the value of the SP or ESP must be within the valid range of the offset address.

Combined with the code in this article, seg_base = 0x7c00,seg_limit = 0xffffe,g = 1, the effective bounds are

0xFFFFE * 0x1000 + 0xFFF = 0xffff_efff;

Then the valid range of offset addresses is [0xffff_f000, 0XFFFF_FFFF]

Assuming that the initial value of ESP is 0, this time to execute push eax, is it legal?

Analysis: ESP subtracts 4, equals 0XFFFF_FFFC, and then (if legal) the value of EAX is written to four storage units offset to 0XFFFF_FFFC~0XFFFF_FFFF, because these offsets are within the valid range, so there is no problem.

Assuming that the initial value of ESP is 1, this time to execute push eax, is it legal?

Analysis: ESP subtracts 4, equals 0XFFFF_FFFD, and then (if legal) the value of EAX is written to four storage units offset to 0xffff_fffd~0xffff_ffff,0x0000_0000, because offset 0 is not in the valid range, so an exception is thrown.
Simulating this in Bochs, we found that the CPU was restarted.

For pop instructions, that's the truth.

Assuming that the initial value of the ESP is 0XFFFF_FFFC, when performing pop eax, is it legal?

Analysis: If it is legal, then the contents of the four storage units that are offset to 0XFFFF_FFFC~0XFFFF_FFFF will be transferred to EAX, then esp+4=0, obviously 0xffff_fffc~0xffff_ffff is a valid offset, so it is allowed to execute. Such as:

Assuming that the initial value of the ESP is 0XFFFF_FFFD, when performing pop eax, is it legal?

Analysis: If it is legal, then the contents of the four storage units that are offset to 0xffff_fffd~0xffff_ffff,0x0000_0000 will be transferred to EAX and then esp+4=1; obviously 0 is not a valid offset, so execution is not allowed. Such as:

Back to our code, because ESP only provides offset addresses, true physical address = Offset Address + segment base address, so for the stack in this code, the combined segment base address = 0x7c00, valid offset addresses = [0xffff_f000, 0xffff_ffff], so

The lowest-end valid Physical address = 0x7c00 + 0xffff_f000 = 0x6c00 (carry is discarded)

High-end valid Physical address = 0x7c00 + 0XFFFF_FFFF = 0x7BFF (carry is discarded)

In other words, the current program defines a stack space between the physical address 0X6C00~0X7BFF. Size is (0x7bff-0x6c00 + 0x01 =0x1000) 4KB;

4. Protection when modifying the segment register
         The following enters the protection mode ...         jmp DWORD 0x0010:flush             ; 16-bit Descriptor Selector Sub: 32-bit offset
         [bits] + +  flush:         eax,0x0018 mov           ds,eax      62         mov eax,0x0008                     ; load data Segment (0..4GB) Select sub-           es,eaxmov           , eax           gs,eaxmov         eax,0x0020                     ; 0000 0000 0010 000068        mov ss,eax         xor Esp,esp                        ; ESP <-0

In line 55th, this instruction implicitly modifies CS, and the instructions that modify the register also appear in the 58~68 line (bold section).

The instructions above involve all segment registers, and when these instructions are executed, the processor transmits the selector given in the instruction to the selector portion of the segment register (which is the 16-bit visible part). However, the firmware of the processor will check the following before it completes the transfer:

(1) Check index number

Requirement: Descriptor index in segment selection sub * 8 + 7 <= GDT (or LDT) boundary value

If the requirement is not met, an exception of 13 is generated, and the original value in the segment register is unchanged.

(2) Check the category of the descriptor

The original Book table 12-1, I am here to draw a copy.

Y: Indicates allow

N: Indicates not allowed

Example: SS only allows read and write data segments to be loaded.

Also, be aware that:

    • Code snippets are not writable at all times
    • For Ds,es,fs,gs, you can load a select child with a value of 0 (but will cause an exception when accessed)
    • For CS and SS, it is not allowed to pass a selector of value 0 to it

(3) Check P-bit

If P=0, indicates that the segment pointed to by the descriptor does not exist in physical memory. At this point, the processor aborts processing and throws an exception.

If P=1, the processor Fugazai the segment description to the descriptor cache register, while placing a bit (limited to the memory segment descriptor currently discussed)

The content of this blog is here. The rest of the 12th chapter, please refer to memory Protection (ii)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 19

Memory protection (i)--"x86 assembly language: From the actual mode to the protection mode" Reading notes 18

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.