`

(第三章 11)根据自己内存情况 使用分页机制

 
阅读更多

一、查看内存分布情况

      设置“页目录表”和“页表”之前,最好先查看下内存分布情况,根据“OS可用内存的大小”来设置她们;否则可能设置了太大的“页目录表”和“页表”而浪费了宝贵的内存。

      如果傻乎乎地设置“页目录表”和“页表”,我们来看看后果:

      假设内存的一个物理块是4KB(=4096B)。我们知道,“页目录表”占用一个内存物理块,而“页目录表”中的每项PDE占32bit(4B),因此“页目录表”中最多有4096B/4B=1024个PDE;1024个PDE对应1024个页表,而每个“页表”又占用一个物理内存块。综上,

      “页目录表”占用内存  =4KB

      “页表”占用内存        =1024*4KB   =4MB

     ∴仅仅是“页目录表”和“页表”这种索引性质的东西(还不是真正要加载到内存的代码和数据)就占用了4MB+4KB

 

%include "pm.inc" ; 常量, 宏, 以及一些说明

 

PageDirBase equ 200000h ; 页目录开始地址: 2M

PageTblBase equ 201000h ; 页表开始地址: 2M + 4K

 

org 0100h

jmp LABEL_BEGIN

 

[SECTION .gdt]

; GDT

;                                         段基址,       段界限     , 属性

LABEL_GDT: Descriptor       0,                 0, 0 ; 空描述符

LABEL_DESC_NORMAL: Descriptor       0,            0ffffh, DA_DRW ; Normal 描述符

LABEL_DESC_PAGE_DIR: Descriptor   PageDirBase,              4096-1, DA_DRW ; Page Directory

LABEL_DESC_PAGE_TBL: Descriptor   PageTblBase,      4096 * 8 - 1, DA_DRW ; Page Tables

LABEL_DESC_CODE32: Descriptor       0,  SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32

LABEL_DESC_CODE16: Descriptor       0,            0ffffh, DA_C ; 非一致代码段, 16

LABEL_DESC_DATA: Descriptor       0, DataLen - 1, DA_DRW ; Data

LABEL_DESC_STACK: Descriptor       0,        TopOfStack, DA_DRWA + DA_32 ; Stack, 32 位

LABEL_DESC_VIDEO: Descriptor 0B8000h,            0ffffh, DA_DRW ; 显存首地址

; GDT 结束

 

GdtLen equ $ - LABEL_GDT ; GDT长度

GdtPtr dw GdtLen - 1 ; GDT界限

dd 0                         ; GDT基地址,等一会儿在.s16这个实模式段中将GDT的基地址放到[GdtPtr+2]开头的4个字节中的,现在先不着急,先用0初始化即可。

 

                        ; 等一会儿会使用命令 lgdt [GdtPtr] 加载GdtPtr这6个字节到寄存器GDTR中

 

 

; GDT 选择子

SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT

SelectorPageDir equ LABEL_DESC_PAGE_DIR - LABEL_GDT

SelectorPageTbl equ LABEL_DESC_PAGE_TBL - LABEL_GDT

SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT

SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT

SelectorData equ LABEL_DESC_DATA - LABEL_GDT

SelectorStack equ LABEL_DESC_STACK - LABEL_GDT

SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

; END of [SECTION .gdt]

 

[SECTION .data1] ; 数据段

ALIGN 32

[BITS 32]

LABEL_DATA:

; 实模式下使用这些符号 (i.e. _szPMMessage)

; 字符串

_szPMMessage: db "In Protect Mode now. ^-^", 0Ah, 0Ah, 0 ; 进入保护模式后显示此字符串

_szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh   Type", 0Ah, 0 ; 进入保护模式后显示此字符串

_szRAMSize db "RAM size:", 0

_szReturn db 0Ah, 0

; 变量

_wSPValueInRealMode dw 0

_dwMCRNumber: dd 0 ; Memory Check Result  -->  放置ARDS结构数组的结构元素个数

_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。

_dwMemSize: dd 0

_ARDStruct: ; Address Range Descriptor Structure

_dwBaseAddrLow: dd 0

_dwBaseAddrHigh: dd 0

_dwLengthLow: dd 0

_dwLengthHigh: dd 0

_dwType:  dd 0

 

_MemChkBuf: times 256 db 0

 

; 保护模式下使用这些符号(i.e. szPMMessage)

 

szPMMessage equ _szPMMessage - $$

szMemChkTitle equ _szMemChkTitle - $$

szRAMSize equ _szRAMSize - $$

szReturn equ _szReturn - $$

dwDispPos equ _dwDispPos - $$

dwMemSize equ _dwMemSize - $$

dwMCRNumber equ _dwMCRNumber - $$

ARDStruct equ _ARDStruct - $$

dwBaseAddrLow equ _dwBaseAddrLow - $$

dwBaseAddrHigh equ _dwBaseAddrHigh - $$

dwLengthLow equ _dwLengthLow - $$

dwLengthHigh equ _dwLengthHigh - $$

dwType equ _dwType - $$

MemChkBuf equ _MemChkBuf - $$

 

DataLen equ $ - LABEL_DATA

; END of [SECTION .data1]

 

 

; 全局堆栈段

[SECTION .gs]

ALIGN 32

[BITS 32]

LABEL_STACK:

times 512 db 0

 

TopOfStack equ $ - LABEL_STACK - 1

 

; END of [SECTION .gs]

 

 

[SECTION .s16]

[BITS 16]

LABEL_BEGIN:

mov ax, cs

mov ds, ax

mov es, ax

mov ss, ax

mov sp, 0100h            ;注:(软件)堆栈由程序人员在存储器中划出的一块存储区,向地址减小的方向堆积。

 

mov [LABEL_GO_BACK_TO_REAL+3], ax

mov [_wSPValueInRealMode], sp

 

; 得到内存数-------------------------------->代码1

mov ebx, 0

mov di, _MemChkBuf

.loop:

mov eax, 0E820h

mov ecx, 20

mov edx, 0534D4150h

int 15h                                              ;调用这个中断,下一块内存的信息会被放入[es:di]

 

         ; BIOS中断  和  DOS中断

         ; bios中断(int 1~20h)是主板预装好的BIOS提供的功能;dos中断(int 21H)则需要使用操作系统。调用方式都是int #. 例如,例如,

         ; INT 17H是打印机I/O调用的BIOS中断,(1)当AH=0时,把AL中的字符在打印机上打印出来;(2)当AH=1时,把AL中的初始化控制命令传送给打印机;(3)当AH=2时,把打印机的状态读至AL寄存器。这里17H是中断号,AH是功能号,AL是调用参数,(1)可以简记为“INT 17H/0”.

         ; 注:BIOS,实际上就是微机的基本输入输出系统(Basic Input-Output System),其内容集成在微机主板上的一个ROM芯片上,主要保存着有关微机系统最重要的基本输入输出程序,系统信息设置、开机上电自检程序和系统启动自举程序等。

         ; BIOS功能主要包括以下方面:一是BIOS中断服务程序,即微机系统中软件与硬件之间的一个可编程接口,主要用于程序软件功能与微机硬件之间实现衔接。操作系统对软盘、硬盘、光驱、键盘、显示器等外围设备的管理,都是直接建立在BIOS系统中断服务程序的基础上,操作人员也可以通过访问 INT 5、INT 13等中断点而直接调用BIOS中断服务程序。二是BIOS系统设置程序,前面谈到微机部件配置记录是放在一块可读写的CMOS RAM芯片中的,主要保存着系统基本情况、CPU特性、软硬盘驱动器、显示器、键盘等部件的信息。在BIOS ROM芯片中装有“系统设置程序”,主要用来设置CMOS RAM中的各项参数。这个程序在开机时按下某个特定键即可进入设置状态,并提供了良好的界面供操作人员使用。事实上,这个设置CMOS参数的过程,习惯上也称为“BIOS设置”。第三是POST上电自检程序,微机按通电源后,系统首先由POST(Power On Self Test,上电自检)程序来对内部各个设备进行检查。通常完整的POST自检将包括对CPU、640K基本内存、1M以上的扩展内存、ROM、主板、 CMOS存贮器、串并口、显示卡、软硬盘子系统及键盘进行测试,一旦在自检中发现问题,系统将给出提示信息或鸣笛警告。第四为BIOS系统启动自举程序,系统在完成POST自检后,ROM BIOS就首先按照系统CMOS设置中保存的启动顺序搜寻软硬盘驱动器及CD—ROM、网络服务器等有效地启动驱动器,读入操作系统引导记录,然后将系统控制权交给引导记录,并由引导记录来完成系统的顺利启动。

         ; 这么看来,int 15h是一个BIOS中断调用咯! 关于int 15h, 详见这里http://blog.csdn.net/gxfan/article/details/2962549

 

 

jc LABEL_MEM_CHK_FAIL       ;若CF==0,则出错

 

add di, 20

inc dword [_dwMCRNumber]

cmp ebx, 0

jne .loop                                            ;若CF==0, ebx==0,则还有下一块内存的信息

 

jmp LABEL_MEM_CHK_OK

LABEL_MEM_CHK_FAIL:

mov dword [_dwMCRNumber], 0

LABEL_MEM_CHK_OK:

 

; 初始化 16 位代码段描述符

        ;;;;;;;;;;;;将16位代码段段基址放到eax中;;;;;;;;;;;;

mov ax, cs

movzx eax, ax

shl eax, 4

add eax, LABEL_SEG_CODE16

        ;;;;;;;;;;;将段基址放到相应位置;;;;;;;;;;;

mov word [LABEL_DESC_CODE16 + 2], ax

shr eax, 16

mov byte [LABEL_DESC_CODE16 + 4], al

mov byte [LABEL_DESC_CODE16 + 7], ah

 

; 初始化 32 位代码段描述符

xor eax, eax

mov ax, cs

shl eax, 4

add eax, LABEL_SEG_CODE32

mov word [LABEL_DESC_CODE32 + 2], ax

shr eax, 16

mov byte [LABEL_DESC_CODE32 + 4], al

mov byte [LABEL_DESC_CODE32 + 7], ah

 

; 初始化数据段描述符

xor eax, eax

mov ax, ds

shl eax, 4

add eax, LABEL_DATA

mov word [LABEL_DESC_DATA + 2], ax

shr eax, 16

mov byte [LABEL_DESC_DATA + 4], al

mov byte [LABEL_DESC_DATA + 7], ah

 

; 初始化堆栈段描述符

xor eax, eax

mov ax, ds

shl eax, 4

add eax, LABEL_STACK

mov word [LABEL_DESC_STACK + 2], ax

shr eax, 16

mov byte [LABEL_DESC_STACK + 4], al

mov byte [LABEL_DESC_STACK + 7], ah

 

; 为加载 GDTR 作准备

xor eax, eax

mov ax, ds

shl eax, 4

add eax, LABEL_GDT ; eax <- gdt 基地址

mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址

 

; 加载 GDTR

lgdt [GdtPtr]

 

; 关中断

cli

 

; 打开地址线A20 (将92端口一个字节的第1位置为1)

in al, 92h                          --> 从92端口读一个字节到al

or al, 00000010b

out 92h, al                          --> 将al持有的数据写到92端口

 

 

; 准备切换到保护模式

mov eax, cr0

or eax, 1

mov cr0, eax

 

; 真正进入保护模式

jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里

mov ax, cs

mov ds, ax

mov es, ax

mov ss, ax

 

mov sp, [_wSPValueInRealMode]

 

in al, 92h ; ┓

and al, 11111101b ; ┣ 关闭 A20 地址线

out 92h, al ; ┛

 

sti ; 开中断

 

mov ax, 4c00h ; ┓

int 21h ; ┛回到 DOS

 

         ; 上面是一个DOS中断调用(不是BIOS中断调用), int 21h中的21h是中断号,AH=4ch是“功能号”,AL=00h是“中断调用参数”。这里的功能是“带返回码结束,AL=返回码”。

; END of [SECTION .s16]

 

 

[SECTION .s32]; 32 位代码段. 由实模式跳入.

[BITS 32]

 

LABEL_SEG_CODE32:

mov ax, SelectorData

mov ds, ax ; 数据段选择子

mov ax, SelectorData

mov es, ax

mov ax, SelectorVideo

mov gs, ax ; 视频段选择子

 

mov ax, SelectorStack

mov ss, ax ; 堆栈段选择子

 

mov esp, TopOfStack

 

 

; 下面显示一个字符串,用法详见后面“保护模式下显示字符串”

 

	push	szPMMessage
	call	DispStr
	add	esp, 4

 

push szMemChkTitle

call DispStr

add esp, 4

 

call DispMemSize ; 显示内存信息

 

call SetupPaging ; 启动分页机制

 

; 到此停止

jmp SelectorCode16:0

 

 

; 启动分页机制 --------------------------------------------------------------

SetupPaging:

;1、计算出最大地址为[dwMemSize]对应的内存共有多少个页表(也即PDE个数,不是页面个数),将个数(ecx,32bit)压栈

xor edx, edx

mov eax, [dwMemSize]  ;根据自己机器的实际内存大小来设置页目录表和页表

mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小(一个页面是4k,一个页表有1024个页面)

div ebx             ; edx:eax / ebx ==> eax ...... edx

mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数

test edx, edx

jz .no_remainder

inc ecx ; 如果余数不为 0 就需增加一个页表

.no_remainder:

push ecx ; 暂存页表个数


; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.


;2、首先初始化“页目录表”(即初始化每个PDE)

mov ax, SelectorPageDir ; 此段首地址为 PageDirBase

mov es, ax

xor edi, edi

xor eax, eax

mov eax, PageTblBase | PG_P  | PG_USU | PG_RWW

.1:

stosd                           ; eax中的4个字节 -> es:edi ,每循环一次是一个PDE

add eax, 4096 ; 为了简化, 所有页表在内存中是连续的.

loop .1                      ; 循环次数为ecx=PDE个数


;3、再初始化所有“页表”,即初始化每个PTE

mov ax, SelectorPageTbl ; 此段首地址为 PageTblBase

mov es, ax

pop eax ; 页表个数,也是PDE个数

mov ebx, 1024 ; 每个页表 1024 个 PTE

mul ebx                     ; eax*ebx==>积edx:eax

mov ecx, eax ; PTE个数 = 页表个数 * 1024

xor edi, edi

xor eax, eax

mov eax, PG_P  | PG_USU | PG_RWW

.2:

stosd                           ; eax==>es:edi

add eax, 4096 ; 每一页指向 4K 的空间

loop .2                      ; 循环次数为ecx=PTE个数


;4、开启页表机制

mov eax, PageDirBase

mov cr3, eax


mov eax, cr0

or eax, 80000000h

mov cr0, eax


jmp short .3

.3:

nop


ret

; 分页机制启动完毕 ----------------------------------------------------------

 

 

DispMemSize:

push esi

        push edi

push ecx

 

mov esi, MemChkBuf

mov ecx, [dwMCRNumber];for(int i=0;i<[MCRNumber];i++)//每次得到一个ARDS

 

      ;注意到, ds:esi ==> MemChkBuf ,是一个线性结构;  es:edi ==> ARDStruct,是二维数组

 

.loop:  ;{

mov edx, 5  ;  for(int j=0;j<5;j++) //每次得到一个ARDS中的成员

mov edi, ARDStruct  ;  {//依次显示BaseAddrLow,BaseAddrHigh,LengthLow,

.1:  ;             LengthHigh,Type

push dword [esi]  ;

call DispInt  ;    DispInt(MemChkBuf[j*4]); //显示一个成员,一个成员有四个字节dword

pop eax           ;    db-> BYTE,  dw->WORD,  dd->DWORD

stosd  ;    ARDStruct[j*4] = MemChkBuf[j*4];       stosd指令:将eax的四个字节放到es:edi(ARDStruct)中

add esi, 4  ;

dec edx  ;

cmp edx, 0  ;

jnz .1           ;  }

call DispReturn  ;  printf("\n");

 

cmp dword [dwType], 1          ;  if(Type == AddressRangeMemory)         ; 通过上面stosd,已经填充好了dwType

jne .2                            ;  {

mov eax, [dwBaseAddrLow] ;

add eax, [dwLengthLow]       ;

cmp eax, [dwMemSize]          ;    if(BaseAddrLow + LengthLow >= MemSize)

jb .2   ;    jb==jump below

mov [dwMemSize], eax          ;MemSize = BaseAddrLow + LengthLow; 等号右边是当前这个内存块最后一个字节的地址

.2:   ;  }

loop .loop   ;}

  ;

call DispReturn                    ;printf("\n");

push szRAMSize   ;

call DispStr   ;printf("RAM size:");

add esp, 4   ;

  ;

push dword [dwMemSize] ;

call DispInt   ;DispInt(MemSize);

add esp, 4   ;

 

pop ecx

pop edi

pop esi

ret

 

%include "lib.inc" ; 库函数

 

SegCode32Len equ $ - LABEL_SEG_CODE32

; END of [SECTION .s32]

 

 

; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式

[SECTION .s16code]

ALIGN 32

[BITS 16]

LABEL_SEG_CODE16:

; 跳回实模式:

mov ax, SelectorNormal

mov ds, ax

mov es, ax

mov fs, ax

mov gs, ax

mov ss, ax

 

mov eax, cr0

and     eax, 7FFFFFFEh          ; PE=0, PG=0

mov cr0, eax

 

LABEL_GO_BACK_TO_REAL:

jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值

 

Code16Len equ $ - LABEL_SEG_CODE16

 

; END of [SECTION .s16code]

 

**********************************************************************************************************************************

 

 

代码1执行结果如下图:


 

**********************************************************************************************************************************

 

 

 

程序效果示意图:


 

        可以看到,我的电脑可以使用的内存确实能达到4G(FFFC0000 h + 00040000 h=1 0000 0000 h ==> 4GB),但可供OS使用的内存大小范围仅到32GB(type=1, 00100000 h+01EF0000 h = 1FF0000 h ==> 32MB). 

 

二、初始化页目录表、页表、开启分页机制

 

      知道哪些内存可以使用后,我们就可以节省地 构造自己的“页目录表”和“页表”,并开启分页机制了。代码在上面已经给出,即SetupPaging 这个函数。

 

三、一个细节——保护模式下显示字符串

 

      这里讲“保护模式下实现字符串”主要是分析一下上面程序中调用到的一个函数DispStr,并无涉及对本节课程的理解。

 

DispStr调用方法:

 

[SECTION .data1]
[BITS 32]
...
_szPMMessage:	db	"In Protect Mode now. ^-^",0Ah,0Ah,0	;保护模式显示
szPMMessage	equ	_szPMMessage - $$
...
	push  szPMMessage                  ;将要显示的字符串指针入栈
	call  DispStr
	add   esp,  4                                  ;将显示了的字符串指针出栈

 

 

 

DispStr实现:

 

DispStr:

push ebp

mov ebp, esp       ;-->此后,esp中放的是TopOfStack指针,指向栈顶

push ebx

push esi

push edi

 

mov esi, [ebp+8]   ;取出在函数DispStr调用前被压栈的那个”字” szPMMessage

mov edi, [dwDispPos]

;初始时_dwDispPos: dd (80 * 6 + 0) * 2; 屏幕第6行, 第0列,是屏幕上下一个显示的位置

;dwDispPos equ _dwDispPos - $$

 

mov ah, 0Fh

 

.1:

lodsb ;lodsb-->将esi中的一个字节放到AL中

test al, al

jz .2 ;是结束字符0

cmp al, 0Ah;

jnz .3 ;是“非回车的字符”

 

;;;;;;;;;;;;;;;;是“回车”的时候;;;;;;;;;;;;;;;;

;1) 求得下一行的行数

push eax

mov eax, edi           ;ax(=edi),为被除数(16bit)

mov bl, 160 ;bl,为除数(8bit)

div bl                   ;ah为余数,al为商

 

and eax, 0FFh ;将余数去掉,eax为商(即当前字符的“行数”)

inc eax ;eax为下一行的行数

;2) 将edi指向显存中下一行的第一个字符处

mov bl, 160 ;一行80个字符,一个字符对应显存中的2byte

mul bl ;bl寄存器中的值乘上al寄存器中的值,积在ax中

mov edi, eax

pop eax

jmp .1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

.3: ;是“非回车的字符”

mov [gs:edi], ax

add edi, 2

jmp .1

.2: ;是结束字符0

mov [dwDispPos], edi

 

pop edi

pop esi

pop ebx

pop ebp

ret

 

 

注意:

1)  mov esi, [ebp+8] 取出字符串指针szPMMessage

;

;  |-----------------------|

 

;  |      edi                   | <== ebp

;  |-----------------------|

 

;  |      esi                   | <== ebp+2

;  |-----------------------|

 

;  |      ebx                  | <== ebp+4

;  |-----------------------|

 

;  |      ebp                  | <== ebp+6

;  |-----------------------|

;  |  szPMMessage  | <== ebp+8

;  |-----------------------|

 

;  |            ***              |

 

 

;  |-----------------------|

 

 

其中,edi,esi,ebx,ebp是在函数DispStr中压入的;szPMMessage是在调用这个函数之前压栈的,这个字符串就是要被显示的字符串

 

   ;  |      ...           |

;  |---------------|

;  |      'I'            | <==szPMMessage/esi均指向这个位置

;  |---------------|

;  |      'n'          |

;  |---------------|

;  |      ' '            |

;  |---------------|

;  |      'P'          |

;  |---------------|

;  |      'r'           |

;  |---------------|

;  |      ...           |

;  |---------------|

 

 

  • 描述: 根据内存状况分页
  • 大小: 17.2 KB
  • 大小: 42.7 KB
分享到:
评论

相关推荐

    疯狂内核之——Linux虚拟内存

    第三章 进程的地址空间 117 3.1 用户态内存分配 117 3.1.1 mm_struct数据结构 118 3.1.2 内核线程的内存描述符 122 3.2 线性区的数据结构 123 3.2.1 线性区数据结构 123 3.2.2 红-黑树算法 126 3.2.3 线性区访问权限...

    深入分析Linux内核源码.chm

    第三章中断机制 3.1 中断基本知识 3.2中断描述符表的初始化 3.3异常处理 3.4 中断处理 3.5中断的后半部分处理机制 第四章 进程描述 4.1 进程和程序(Process and Program) 4.2 Linux中的进程概述 4.3 task_struct...

    自己动手写操作系统

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    最强悍的操作系统学习资料

    第3章 进程描述和控制 解释进程的核心概念,并对进程创建/撤销、进程状态、进程控制、操作系统的执行等进行讲授 重点:PCB、进程状态模型、进程切换、模型切换 难点:进程切换与模型切换 第4章线程、对称多处理和微...

    天书夜谈:从汇编语言到Windows内核编程

     第3章 练习反汇编C语言程序 26  3.1 算法的反汇编 27  3.1.1 算法反汇编代码分析 27  3.1.2 算法反汇编阅读技巧 28  3.2 发行版的反汇编 29  3.3 汇编反C语言练习 33  基础篇 内核编程  本书的第二部分,是...

    天书夜读:从汇编语言到Windows内核编程(完整版一)

     第3章 练习反汇编C语言程序 26  3.1 算法的反汇编 27  3.1.1 算法反汇编代码分析 27  3.1.2 算法反汇编阅读技巧 28  3.2 发行版的反汇编 29  3.3 汇编反C语言练习 33  基础篇 内核编程  本书的第二部分,是...

    从汇编语言到Windows内核编程

    第3章 练习反汇编C语言程序 3.1 算法的反汇编 3.1.1 算法反汇编代码分析 3.1.2 算法反汇编阅读技巧 3.2 发行版的反汇编 3.3 汇编反C语言练习 基础篇 内核编程 本书的第二部分,是编写Windows内核程序缡耩方法的基础...

    天书夜读:从汇编语言到Windows内核编程(完整版 二)

     第3章 练习反汇编C语言程序 26  3.1 算法的反汇编 27  3.1.1 算法反汇编代码分析 27  3.1.2 算法反汇编阅读技巧 28  3.2 发行版的反汇编 29  3.3 汇编反C语言练习 33  基础篇 内核编程  本书的第二部分,是...

    自己动手写操作系统 pdf

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Des criptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    自己动手写操作系统 电子工业出版社 pdf

    第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT...

    Android典型技术模块开发详解

    第3章 Activity(活动) 3.1 什么是任务 3.2 Activity的生命周期 3.3 基本用法 3.3.1 创建Activity 3.3.2 启动Activity 3.3.3 窗口Activity 3.3.4 Activity生命周期验证 3.4 Activity之间通信 3.4.1 Activity传递...

    Windows应用程序捆绑核心编程光盘代码

    第3章 进程之间通信概述及初级技术 54 3.1 引言 54 3.2 进程通信概述 55 3.2.1 Windows进程间标准通信技术的发展 55 3.2.2 应用程序与进程 56 3.2.3 进程之间通信的类型 56 3.3 使用自定义消息通信 57 3.3.1 ...

    Linux2.6内核标准教程(共计8--第3个)

    第3章 内存管理 50 3.1 基础知识 51 3.1.1 存储器地址 51 3.1.2 分段机制 52 3.1.3 分页机制 59 3.2 内核页表的初始化过程 65 3.2.1 启用分页机制 65 3.2.2 构建内核页表 68 3.3 物理内存的描述...

    windows驱动开发技术详解-part2

     第3章 Windows驱动编译环境配置、安装及调试  本章将带领读者一步步对驱动程序进行编译、安装和简单的调试工作。这些步骤虽然简单,但往往困 惑着初次接触驱动程序的开发者。  3.1 用C语言还是用C++语言  ...

    Windows驱动开发技术详解的光盘-part1

     第3章 Windows驱动编译环境配置、安装及调试  本章将带领读者一步步对驱动程序进行编译、安装和简单的调试工作。这些步骤虽然简单,但往往困惑着初次接触驱动程序的开发者。  3.1 用C语言还是用C++语言  ...

    自己动手写操作系统(含源代码).part1

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    自己动手写操作系统(含源代码).part2

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    操作系统实验81

    阅读本书第 6 章。了解 i386 处理器的二级页表硬件机制,EOS 操作系统的分页存储器管理方式,以及进程地址空间的内存分布。3. 实验内容查看 EOS 应用

    C#与.NET技术平台实战演练.part2

    C#借由回收站回收资源10-11使用Finalize方法Finalize对效率的影响10-12编写析构器使用析构器的考虑10-13实现IDisposable接口第11章继承.多态与接口11-l扩充基础类的功能11-1-l继承的语法11-l-2简单的UML描述11-2扩充...

Global site tag (gtag.js) - Google Analytics