操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    在之前的兩天里,我們在自制操作系統上開發了一些簡單APP。

    其中在day20,我們初步開發出了API,并用API實現了幾個匯編寫的APP。

    30天自制操作系統day20:API

    在day21,我們又用同樣的方法開發出了幾個API,然后用C寫了幾個APP,最后,還寫了一個帶窗口的APP。

    30天自制操作系統day21:在自制操作系統上用C開發APP

    其實我們可以繼續寫更加復雜的APP,比如一個文檔瀏覽器,圖片的瀏覽器,一個游戲等。

    不過我們先不那么做。

    在真正的開始在操作系統上大規模的開發APP之前,我們需要把操作系統本身的代碼與應用程序上的代碼隔離起來,也就是說把把操作系統本身的代碼保護起來,對各種APP的代碼有效的管理起來。

    為什么有GDT和IDT?

    GDT是global description table,全局描述表,表里存儲了對內存段的描述。

    IDT是interrupt description table,中斷描述表,表示存儲了中斷函數的地址。

    為什么要有GDT? 因為要對內存里存在的代碼區,數據區進行監控,管理,權限設置。

    當GDT記錄一段內存時,同時會記錄這段內存的權限標志,這標志著這段內存是操作系統可用,還是應用程序可用,指令指針是否能指向這個內存段,如果不能指向這個內存段,說明這個內存段只能存放數據,不能存放代碼。

    如何設置內存塊的權限?我們寫的一個函數set_segmdesc:

    
    set_segmdesc(登記位置A, 內存大小size, 內存開始地址base, 權限ar);

    這個函數在GDT表的第A行登記了一個從base開始的size大小的內存區,這個內存區的權限是ar當ar=0x4092時,標志這個內存區只能存取數據,不能存放代碼,而且特權等級很高

    當ar=0x409a時,標志這個內存區只能存放可讀取執行的代碼,不能寫,而且特權等級很高

    當ar=0x40F2時,標志這個內存區只能存取數據,不能存放代碼,而且特權等級很低

    當ar=0x40Fa時,標志這個內存區只能存可讀取執行的代碼,不能寫,而且特權等級很低

    在GDT表中登記過的內存塊,cpu才會去訪問它,訪問它的時候,會遵守ar設定的權限。一但我們寫的代碼讓cpu不遵守ar設定的權限,就會發生中斷,發生中斷時執行IDT中登記的函數。

    這種保護性的邏輯的實現,不在操作系統中,而在操作系統之前的BIOS中,或者在CPU內部就已經設定好了,寫操作系統的我們只用使用這種邏輯就行了。


    使用GDT去登記內存區域

    我們可以按這樣的方式去設置所有的內存區域的權限:

    #define ADR_IDT			0x0026f800
    #define LIMIT_IDT		0x000007ff
    #define ADR_GDT			0x00270000
    #define LIMIT_GDT		0x0000ffff
    
    #define ADR_BOTPAK		0x00280000
    #define LIMIT_BOTPAK	0x0007ffff
    #define AR_DATA32_RW	0x4092
    #define AR_CODE32_ER	0x409a
    
    // 把內存ADR_GDT=0x0027 0000處作為GDT的首地址
    struct SEGMENT_DESCRIPTOR *gdt=(struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    
    // GDT表中的每一項的結構
    struct SEGMENT_DESCRIPTOR {
    	short limit_low, base_low;
    	char base_mid, access_right;
    	char limit_high, base_high;
    };
    // 使用函數來設置GDT表格中的一行
    void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
    {
    	if (limit > 0xfffff) {
    		ar |=0x8000; /* G_bit=1 */
    		limit /=0x1000;
    	}
    	sd->limit_low=limit & 0xffff;
    	sd->base_low=base & 0xffff;
    	sd->base_mid=(base >> 16) & 0xff;
    	sd->access_right=ar & 0xff;
    	sd->limit_high=((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
    	sd->base_high=(base >> 24) & 0xff;
    	return;
    }
    //設置GDT表格中的第一行,這只從0x0000 0000到0xffff ffff的內存段的屬性是0x4902
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    //設置GDT表格中的第二行
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    //設置GDT表格中的第1003行
    set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
    //設置GDT表格中的第1004行
    set_segmdesc(gdt + 1004, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);

    以上代碼的36行,AR_DATA32_RW=0x4902代表著段的屬性信息:是否操作系統專用,是否可以存放程序,是否可讀,是否可寫等。

    AR_CODE32_ER中的AR,Access Right,即訪問權限。

    要研究0x4092代表著怎樣的訪問權限,需要把0x4902展開成二進制

    0x4092=0b 0100 0000 1001 0010

    可以看到它有64位二進制,這個32位對應著結構體中的

    // GDT表中的每一項的結構,一個8個字節,64位
    struct SEGMENT_DESCRIPTOR {
    	short limit_low, base_low;   // 16位,16位
    	char base_mid, access_right; // 8位,8位
    	char limit_high, base_high;  // 8位,8位
    };

    這個結構體又對應著這個圖



    其中代碼中:

    //設置GDT表格中的第一行,這只從0x0000 0000到0xffff ffff的內存段的屬性是0x4902
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);

    AR_DATA32_RW=0x4092的低8位0x92會給到access_right,表示在這段內存是系統專用的,放在這段內存里的內容是可讀,可寫,但是不能執行,所以只能放數據,如果放了代碼,也不能執行,放了也白放。
    其中0x9=0b1001對應著GDT結構中的P=1,DPL=00,S=1;
    0x2=0b0010對應著TYPE=0010,

    對于0x9的詳細解釋

    p=1 代表當前一行GDT結構是有效的

    p=0 代表當前一行GDT結構是無效的


    DPL是特權級的意思,DPL=00,表示最高特權,DPL=11表示最低特權


    s=1 表示可以放代碼段或者數據

    s=0 表示系統段

    所以,0x9=0b1001表示,p=1,DPL=00,s=1,就指最高特權的可以放代碼或者數據的內存段

    0xf=0b1111,表示:p=1,DPL=11,s=1,表示最低特權,可以放數據或內存


    對于0x2對應type時的詳細解釋

    0x2=0b0010,是對type的設置,type的四位分別表示D,E,W,A 或則C,C,R,A,

    type這4位,如果最高位第3位是0,結合s=1,表示這個內存塊是存放數據的,是可讀的

    此時,

    第2位記錄了自己是否被cpu訪問過,通常用于 debug或者虛擬內存技術使用,用A表示

    第1位表示是否可寫,用W 表示

    第0位表示這段內存是否可擴展,用E表示。

    所以這里0x2=0b0010,最高位第3位=0,表示存放數據,可讀,第1位=1,表示可寫。

    綜合起來,就把這個內存塊記錄為可讀可寫的存放數據用的。


    那么0xa表示什么意思呢?

    如果最高位第3位是1,結合s=1,表示這塊內存是放代碼用的,是可執行的。

    第2位記錄了自己是否被cpu訪問過,通常用于 debug或者虛擬內存技術使用,用A表示

    第1位表示是否可讀,用R 表示

    第0位表示這段內存是否能被訪問,為0表示不能被低特權的代碼訪問,通常是一種權限保護。

    綜合起來,

    0xa=0b1010,表示這塊內存是專門存放代碼用的,可執行的,可讀的。

    那么綜合起來,0x92,表示系統專用的存放數據的可讀可寫的內存塊。

    0xf2,表示應用程序使用的存放數據的可讀可寫的內存塊。

    0x9a表示系統專用的存放代碼的可讀可執行的內存塊。

    0xfa表示應用程序使用的存放代碼的可讀可執行的內存塊。


    0x4092的高四位0x4會給到結構體limit_high的高位,對應著GDT結構圖中的 20--23位,分別表示G,D/B,L,AVL,這四位份別表示是否對應4G內存,16/32位,64位,是否有系統權限。0x4對應的二進制是0x0100,對應著D/B為1,其他都為零,表示32位。

    再注意到,代碼里,有對ar與0x8000進行了或這個操作:

    ar |=0x8000; 

    這相當于把G設置為1,表示段值每改變1,對應內存地址改變4K,4K就是1頁,1Page.

    到此,我們就把函數的第四個參數AR_DATA32_RW的意義說清楚了。

    那么函數的第3個參數0x0000 0000是什么意思?表示此內存塊的開始地址

    函數的第2個參數0xffff ffff是什么意思?這里只取低5位0xf ffff表示此內存塊的結束地址或者結束地址對應的page地址。

    那么從0x0000 0000 到 0xf ffff一共多少個內存地址呢?

    16x16x16x16x16=16x16x4x4x16x16=1M

    表示1M的內存地址?

    如果它是結束地址,那么此內存塊的大小是1M

    如果ar的最高位設置為1,則它表示Page地址,每個Page里含有4K個內存地址,所以4Kx1M=4G,那么此內存塊的大小是4G

    所以,綜合第2個參數0xffff ffff, 第3個參數0x0000 0000,以及第4個參數0x4092,如下代碼:

    //設置GDT表格中的第一行,這只從0x0000 0000到0xffff ffff的內存段的屬性是0x4092
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);

    我們在GDT表中記錄了一個這樣的內存塊:開始地址是0x0000 0000, 結束地址是0xf ffff的內存區域,這個內存區域的大小是1M,它是系統專用的內存,可讀,可寫,不可執行,所以只能存放數據。

    這條記錄放在了GDT表的gdt + 1的位置,表示放在了GDT的第1行。

    由于gdt是結構體SEGMENT_DESCRIPTOR,而這個結構體一共8個字節,所以gdt+1其實表示內存地址+8。


    依據上面的解讀,如下幾句代碼設置的內存塊是怎樣的?

    //設置GDT表格中的第二行,專門存放操作系統代碼的內存
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    //設置GDT表格中的第1003行,專門存放APP代碼的內存
    set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
    //設置GDT表格中的第1004行,專門存放APP數據的內存
    set_segmdesc(gdt + 1004, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);

    在GDT的第2行,設置一個以ADR_BOTPAK=0x0028 0000開頭,大小為LIMIT_BOTPAK=0x0007ffff的內存地址,這段內存地址大小是512K,它的屬性是AR_CODE32_ER=0x409a,表示系統專用,可讀,不可寫,可執行,可執行就是可以存放代碼的地方。總的來說,這塊512K的內存區域,是專門用來存放操作系統代碼的。

    這里,我們注意到, 操作系統放在內存中的什么位置,要占用多大區域的內存,都是我們寫操作系統的人,自己可以指定的。比如上面的代碼就指定了操作系統在內存中存放情況。

    以上代碼還設置了GDT 的第1003行,它在GDT的1003行登記了一個其實地址為p,結束地址為finfo0->size-1的一個內存區域,這塊內存的權限是AR_CODE32_ER + 0x60=0x409a+0x60=0x40fa,表示不是操作系統專用,而是應用程序專用,可讀,不可寫,可執行,綜合來說,表示一塊抓門存放應用程序APP的可執行代碼的內存塊。

    注意到,我們正式利用GDT這個表,登記了哪些內存塊是否可讀,可寫,是給操作系統用,還是給應用程序用,是存放代碼的,還是存放數據的。我們只用登記,登記完后,CPU上的硬件會根據登記的結果,對內存做相應設置。

    設置完后,如果應用程序的代碼,不小心訪問了不該訪問的內存區域,cpu就會產生中斷,

    我們如果想對應用程序的代碼進行這方面的監控,就可以就收這個中斷,并打印出中斷產生中斷時的各種寄存器的值,從而知道是GDT中的那個內存區域的代碼訪問了不該訪問的區域。

    同理,以上代碼第6行,設置了GDT的第1004行,這行表示從q開始的一塊大小為segsize-1的內存,這塊內存的權限是AR_DATA32_RW+0x60=0x40f2,表示應用程序專用的,可讀,可寫,不可執行,所以它表示一塊專用于存放數據的內存。

    了解了GDT表的用途,我們就可以把操作系統的代碼和應用程序的代碼所放的內存區域都在GDT表中進行登記,只要對內存區域做一定的權限設置,就可以限制操作系統與應用程序代碼的自由訪問,從而把操作系統和應用程序隔離起來。

    使用GDT表的權限設置把操作系統和應用程序隔離起來

    根據以上的解析,我們自制的操作系統的代碼的內存區域和數據的內存區域可以這樣登記:

    #define ADR_BOTPAK		0x00280000
    #define LIMIT_BOTPAK	0x0007ffff
    #define AR_DATA32_RW	0x4092
    #define AR_CODE32_ER	0x409a
    // 登記操作系統可以讀寫的內存區域為0x0000 0000 至 0xf ffff * 1K ,一共4G的內存區域
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    // 登記操作系統可以存放代碼的區域為0x0028 0000 至 0x0028+0x7 ffff,一共512K的內存區域
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    

    對我們寫的C語言APP的代碼和數據所要使用的內存區域可以遮掩登記:

    //設置GDT表格中的第1003行,專門存放APP代碼的內存
    set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
    //設置GDT表格中的第1004行,專門存放APP數據的內存
    set_segmdesc(gdt + 1004, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);

    這樣,我們再運行C語言寫的APP的代碼時,就需要把APP的代碼都存放在以p開頭,大小為finfo-size的內存區域里,把APP的數據都存放在以q開頭,大小為segsize的內存區域里。

    這樣登記記錄好后,再把GDT表的1003行里所設置的內存地址,賦值CPU代碼段寄存器ECS,CPU就會去執行p里的代碼了。

    把GDT表的1004行里所設置的內存地址,賦值CPU數據段寄存器EDS,CPU再執行時,凡是需要訪問數據,就會去q里查找數據了。

    不過要實現分開讀取到內存的p和q位置,就需要我們在編譯c源碼得到hrb可執行文件的時候,就把源碼中的代碼和數據分開存放。只有分開存放了,才能分開讀入到內存p和q中。

    對C源碼的編譯

    編譯過程還是去day21的教程:

    30天自制操作系統day21:在自制操作系統上用C開發APP

    這里編譯了一個a.c的c源碼文件

    //將a.c編譯成a.gas
    a.gas : a.c bootpack.h Makefile
    	cc1.exe -I$(INCPATH) -Os -Wall -quiet -o a.gas a.c
    //將a.gas編譯成a.nas
    a.nas : a.gas Makefile
    	gas2nask.exe -a a.gas a.nas
    //將a.nas編譯成a.obj
    a.obj : a.nas Makefile
    	nask.exe a.nas a.obj a.lst
    //將a_nask.nas編譯成a_nask.obj
    a_nask.obj : a_nask.nas Makefile
    	nask.exe a_nask.nas a_nask.obj a_nask.lst
    
    //將a.obj,a_nask.obj編譯為a.bin
    a.bim : a.obj a_nask.obj Makefile
    	obj2bim.exe @$(RULEFILE) out:a.bim map:a.map a.obj a_nask.obj
    //將a.bim編譯為a.hrb
    a.hrb : a.bim Makefile
    	bim2hrb.exe a.bim a.hrb 0

    最終編譯完,得到了 可執行文件a.hrb。

    這個文件的36個字節存放的是文件信息,這36字節就相當于文件結構的說明,我們把這36字節搞清楚了,整個文件的結構就搞清楚了。

    注意到,文件為什么這么存放,我們自己是可以決定的。不用拘泥于此形式。

    其中0x0000-0x0003,4個字節,表示文件希望操作系統給自己分配用于存放數據的內存長度

    0x0004-0x0007,4個字節,是4個字符"Hari",是操作系統的可執行文件的標志。如果沒有這個標志,我們操作系統就不把這個文件看成可執行文件。

    0x0008-0x000b , 4個字節,表示給數據預備的內存地址個數

    0x000c-0x000f , 4個字節,表示棧地址

    0x0010-0x0013, 4個字節,表示hrb內部數據長度

    0x0014-0x0017, 4 個字節,表示hrb內部數據的開始地址

    0x0018-0x001b, 4個字節內的值是:0xe9 00 00 00,那么對應0x001b位置就是0xe9,0xe9正好的 JMP 指令的機器碼。 之前我們運行C程序的時候,要JMP 0x1b才能運行,就是因為跳轉到0x1b后,0x1b位置還是JMP,于是繼續跳轉,跳轉到什么位置呢?跳轉到0x001c內所存儲的地址處。

    0x001c-0x001f,存放C程序的入口相對于0x20的地址。有了這個相對地址,0x1b位置的JMP指令就可以跳轉到C程序的入口地址了。


    明白了C源碼編譯好的可執行文件hrb的文件結構后,就可以把可執行文件中的數據和代碼分開讀取到p和q中,然后再注冊到GDT中。

    把可執行文件的數據和代碼分別放在不同性質的內存段中

    if (finfo !=0) {
    		p=(char *) memman_alloc_4k(memman, finfo->size);
    		file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
    		// 如果文件的第4個字節至第8個字節是“Hari",說明是和執行文件
        if (finfo->size >=36 && strncmp(p + 4, "Hari", 4)==0 && *p==0x00) {
    			// 取文件內準備分配的內存的總長度
          segsiz=*((int *) (p + 0x0000));
          // 取堆棧地址
    			esp=*((int *) (p + 0x000c));
    			// 文件內數據的實際總長度
          datsiz=*((int *) (p + 0x0010));
          // 可執行文件內的數據的開始地址
    			dathrb=*((int *) (p + 0x0014));
          // 用memman找一個segsiz大小的空閑內存空間,用來存放應用程序的數據
    			q=(char *) memman_alloc_4k(memman, segsiz);
    			*((int *) 0xfe8)=(int) q;// 把內存空間的地址存放到0xfe8處,傳遞給中斷函數
    			// 將文件所在的內存空間p登記一下,讓cpu按照一個應用程序的可執行可讀的,用于存放代碼內存塊來管理
          set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
    			// 將文件內數據要存放的內存空間q登記一下,讓cpu按照一個應用程序的可讀寫的,用于存放數據的內存塊來管理
          set_segmdesc(gdt + 1004, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);
    			// 把文件中的數據復制到q中
          for (i=0; i < datsiz; i++) {
    				q[esp + i]=p[dathrb + i];
    			}
          //跳轉到0x1b處開始執行C程序,
          // C程序的代碼是存放在1003*8的,C程序的棧是從esp開始的,C程序的數據是存放在1004*8的
          // C程序執行時,把操作系統的棧備份到task->tss.esp0
          // 當C程序執行完,返回操作系統程序時,從&(task->tss.eps0)處恢復處棧的地址
    			start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0));
    			memman_free_4k(memman, (int) q, segsiz);
    		} else {
    			cons_putstr0(cons, ".hrb file format error.\n");
    		}
    		memman_free_4k(memman, (int) p, finfo->size);
    		cons_newline(cons);
    		return 1;
    	}

    以上代碼,把C編譯好的可執行文件的內存地址p放在了GDT的1003*8處,把C程序編譯好的可執行文件中的數據的內存地址q放在了1004*8處。

    只要把代碼和數據放到不同的內存塊里,然后把內存塊以應用程序的權限記錄到GDT中,CPU就會自動限制內存塊中的代碼的訪問權限,如果這些代碼訪問了那些登記為操作系統用的內存區域,CPU就會產生某個號碼的中斷,我們通過編寫相應的中斷函數,就會知道是在什么位置的代碼在越界訪問。

    這樣,我們就把應用程序的代碼和操作系統的代碼做了隔離,就相當于對操作系統做了保護。

    不過由于應用程度代碼以及數據分別放在了GDT表中登記的不同的內存塊中,所以在執行代碼的時候,就需要設置一下cpu的代碼段寄存器ECS,數據段寄存器EDS,以及棧的寄存器EPS,

    為此,我們新制作了執行應用程序函數start_app, 因為要在這個函數里設置寄存器的值,所以這個函數最好是用匯編寫,這樣設置寄存器方便一些:

    代碼如下:

    _start_app:		; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0);
    		PUSHAD		; 預先備份所有的寄存器       
    		MOV		EAX,[ESP+36]	; EAX=dip
    		MOV		ECX,[ESP+40]	; ECX=cs
    		MOV		EDX,[ESP+44]	; EDX=esp
    		MOV		EBX,[ESP+48]	; EBX=ds
    		MOV		EBP,[ESP+52]	; EBP=tss.esp0
    		MOV		[EBP  ],ESP		; ESP的值備份到tss.esp0中 
    		MOV		[EBP+4],SS		; SS的值備份到tss.esp0+4中
    		MOV		ES,BX         ; 把應用程序的數據地址ds/ss 賦值給段寄存器ES,DS,FS,GS   
    		MOV		DS,BX
    		MOV		FS,BX
    		MOV		GS,BX
    ;	
    		OR		ECX,3			; ECX=1003*8 | 3,因為要訪問特權級為0x11的應用程序段,所以這里將特權級設置為3,即為0x11
    		OR		EBX,3			; EBX=1004*8 | 3  
    		PUSH	EBX				; 將ds入棧
    		PUSH	EDX				; 將esp入棧
    		PUSH	ECX				; 將cs入棧
    		PUSH	EAX				; 將eip入棧
    		RETF            ; 返回棧頂所代表的代碼位置處執行,即eip位置處執行,這就成功了執行了C程序
    ;這里,利用RETF返回到了應用程序APP處執行,并沒有使用CALL或者JMP,因為當利用GDT將內存區域隔離起來之后
    ;從當前所處的GDT的2*8位置所登記的內存塊中是無法直接跳轉到GDT的1003*8位置所登記的內存塊中去執行程序的
    ;只能通過RETF指令去返回。那如何使RETF指令返回到APP的代碼處呢?先將APP代碼的地址push 入棧
    然后再RETF就可以跳轉到1003*8位置了

    這里為什么要將 1003*8 | 3 ?

    因為我們要使RETF能夠跳轉到1003*8所登記的內存地址處。

    為什么一定要OR 一個3才能跳轉到1003*8所登記的內存地址處呢?

    因為CPU要跳轉到GDT的1003*8處時,中間是有步驟的.

    1003*8的計算有點復雜,我們假設訪問的是3*8,步驟是:

    1. 把3*8,翻譯成16進制0x0000 3000

    2. 此時用它的高5位0x00003, 表示GDT中的第0x00003行

    3. 然后看3*8的第2位的值,第2位是0,表示CPU要訪問GDT。如果第2位是1,表示CPU要訪問GDT中的子表LDT。[這里還沒有用到LDT,GDT與LDT的結構一樣,但是目的不同。GDT是為了保護操作系統的內存段不被破環,而LDT主要是為了保護應用程序的內存度不被破環]

    4. 然后看3*8的第1,0位的值,這兩位表示CPU要跳轉的內存段的特權級。如果這兩位的值與GDT表0x00003行登記的特權級相同,或者高,那么CPU就會可以跳轉到0x00003所登記的內存塊去。如果這兩位的值與GDT表0x00003行登記的特權級低,那么就無法訪問,并且CPU還會產生訪問異常的中斷。


    為什么只要在GDT中登記一下內存的權限,這段內存就被保護起來了?

    就是因為CPU在按照地址去訪問內存塊的時候,地址中是包含著特權級的。只有地址中包含的特權級高于GDT表中登記的特權級時,CPU才能去訪問。否則,就會收到異常訪問的中斷。


    經過上述start_app函數里對寄存器的設置,對GDT地址中特權值的設置,通過RETF,就可以成功跳轉到1003*8所指向的APP所在的內存地址了,就可以跳轉過去執行APP的代碼了。

    也就是說,APP可以運行了。

    然后就會按照APP中的代碼一行行運行了。

    不過這里,我們只是跳轉過去執行APP代碼了,并沒有等這個代碼執行完后,再返回到運行start_app函數的程序處。

    也就是說,我們使用RET的方法跳轉到APP的代碼處,后,這個程序是無法再返回到調用start_app程序中繼續運行的。

    解決start_app的返回問題

    辦法有一個,就是不再使用ret返回,轉而在0x40中斷函數中返回。

    要想從中斷函數中返回,就必須把調用start_app時的地址放入ESP,然后RET。

    假設我們已經得到了start_app時的地址,這個地址就在EAX中,那么就可以用如下代碼返回到調用start_app的命令行程序中。

    _asm_end_app:
    		MOV		ESP,[EAX] ;把地址給到ESP,此時如果RET的時候,就會回到ESP+1處所保存的地址處,ESP所保存的地址處,就是調用start_app的命令行程序處。
    		MOV		DWORD [EAX+4],0
    		POPAD            
    		RET					; 回到ESP所指向的地址

    好既然能夠返回了,那么如何得到這個棧頂ESP呢?

    考慮到中斷函數其實是屬于操作系統內部函數的,所以我們可以在中斷函數中,直接獲取到棧的地址。其實當前操作系統任務task正在運行,不如在操作系統task中的tss中記錄一下esp,tss中本來就有esp這一項。記錄一下也方便。

    如果在task中完成了棧頂的記錄,那么就可以用task_now()取到task了,只要取到了task就可以取到棧頂了,按照這個思路,改寫一下中斷函數har_api

    int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
    {
    	int ds_base=*((int *) 0xfe8);
    	struct TASK *task=task_now();// 取得task
    	struct CONSOLE *cons=(struct CONSOLE *) *((int *) 0x0fec);
    	struct SHTCTL *shtctl=(struct SHTCTL *) *((int *) 0x0fe4);
    	struct SHEET *sht;
    	int *reg=&eax + 1;
    	if (edx==1) {
    		cons_putchar(cons, eax & 0xff, 1);
    	} else if (edx==2) {
    		cons_putstr0(cons, (char *) ebx + ds_base);
    	} else if (edx==3) {
    		cons_putstr1(cons, (char *) ebx + ds_base, ecx);
    	} else if (edx==4) {// edx=4時,返回命令行窗口的棧地址
    		return &(task->tss.esp0);// 從task中取得棧頂地址
    	} else if (edx==5) {
    		sht=sheet_alloc(shtctl);
    		sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);
    		make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);
    		sheet_slide(sht, 100, 50);
    		sheet_updown(sht, 3);	/* 3???¢?¤???3?ítask_a?ì?? */
    		reg[7]=(int) sht;
      }
    	return 0;
    }

    好解決了棧頂傳遞的問題,我們還需要把中斷函數相關的幾個函數_asm_hrb_api, hrb_api,和_asm_end_app連一下:

    _asm_hrb_api:
    		STI
    		PUSH	DS
    		PUSH	ES
    		PUSHAD		; 
    		PUSHAD		; 
    		MOV		AX,SS
    		MOV		DS,AX		;
    		MOV		ES,AX
    		CALL	_hrb_api
    		CMP		EAX,0		; 將保存在EAX中的_hrb_api中的返回值與0比較
    		JNE		_asm_end_app 如果返回值不為0,說明調用的是edx=4時,此次返回的是棧頂的地址,那么此時應該跳轉到_asm_end_app中去執行
    		ADD		ESP,32  ; 如果返回值為0,就丟棄掉第二次PUSHAD的內容
    		POPAD         ; 恢復寄存器的值
    		POP		ES			; 
    		POP		DS
    		IRETD         ; 中斷函數正常返回,誰調用中斷函數就返回到哪里
    
    _asm_end_app:
    		MOV		ESP,[EAX]
    		MOV		DWORD [EAX+4],0
    		POPAD
    		RET					; 

    通過比較hrb_api的返回值,如果返回值不為0,就說明是調用了edx=4的中斷函數,此時我們利用asm_end_app返回命令行程序。

    既然我們用中斷函數來返回到命令行程序了,我們就把使用edx=4的函數寫一下,讓C語言程序調用一下,返回到命令行程序中。


    用新的返回方法編寫C程序

    void api_putchar(int c);
    void api_end(void);
    
    void HariMain(void)
    {
    	api_putchar('h');
    	api_putchar('e');
    	api_putchar('l');
    	api_putchar('l');
    	api_putchar('o');
    	api_end();
    }

    這個程序中的api_end,還是要用匯編來寫,寫在a_nask.nas中:

    _api_end:	; void api_end(void);
    		MOV		EDX,4  // 令edx=4
    		INT		0x40   // 調用0x40號中斷
    

    寫完后,編譯,就可以看到程序正常地運行了。


    總結

    今天,我們主要是使用GDT把操作系統和應用程序所使用的內存空間隔離起來。

    我們先把C程序的數據單獨編譯到了文件的某一部分。

    然后又把數據單獨存在了一塊內存中,和代碼存的內存分開。

    然后又把這兩塊內存分別登記在GDT表中,并且設置好權限。利用CPU訪問GDT時,對特權級的驗證,來把操作系統與應用程序的內存地址隔離開來,形成對操作系統的保護。

    GDT可以保護操作系統的內存不被無權限的訪問,但應用程序的內存該如何保護呢?

    假設現在有2個APP應用程序,這兩個應用程序在GDT中都登記了存放數據內存和存放代碼內存。

    那么登記的特權級都是0x11.

    我們說特權級相同,就可以相互訪問。

    所以,這兩個應用程序的內存空間是可以相互訪問的。

    這就壞了,如果有人寫了一個程序,可以訪問微信的數據,那不就會現數據泄漏了么?

    所以,我們還要想辦法讓APP不能夠相互訪問內存段。也就是說,要把APP的數據內存區和代碼內存區保護起來,不讓其他APP訪問。

    其實,只要設置一個LDT表,把應用程序的數據內存,程序內存,棧內存登記到LDT表中,并且設置好權限,那么應用程序的數據內存、程序內存、棧內存就會被保護起來了。

    保護機制和GDT表一樣。

    LDT其實想GDT表結構非常像。

    只不過GDT是主要把操作系統和應用程序隔離開。

    而LDT是把當前運行的應用程序和其他應用程序隔離開。

    他們的保護定向不同,一個保護操作系統,一個保護應用程序APP。

    單位:元

    2.419%

    估值日期

    基金代碼

    基金名稱

    份額凈值/萬份收益/百份收益

    份額累計凈值/七日年化收益率(%)

    2019/04/15

    001014

    中融融安混合

    0.9664

    001387

    中融新經濟混合A

    1.672

    2.104

    2019/04/15

    001388

    中融新經濟混合C

    1.048

    003085

    中融銀行間0-1年中高等

    級信用債指數A

    中融銀行間0-1年中高等

    級信用債指數C

    1.0482

    003086

    1.0415

    004671

    中融核心成長

    0.7851

    005931

    中融恒裕純債A

    1.0050

    1.0150

    2019/04/15

    005932

    中融恒裕純債C

    1.0048

    1.0148

    基金代碼(主基金代碼)

    分級代碼(非分級則為主基金代碼)

    基金簡稱

    份額凈值

    累計凈每萬份基金7日年化估值日

    值 已實現收益收益率 期

    163804

    163804

    中銀收益混合

    2019-04-15

    1.30463.1496

    960012

    中銀收益混合H類1.30851.5535

    2019-04-15

    163816

    163816

    中銀轉債增強債券

    A 1.988 1.988

    163817

    中銀轉債增強債券

    B 1.930 1.930

    2019-04-15

    002180

    002180

    中銀移動互聯混合0.889 0.8890

    2019-04-15

    003966

    003966

    中銀潤利混合

    中銀潤利混合A 1.03541.1554

    003967

    中銀潤利混合C 1.03391.1529

    2019-04-15

    000539

    000539

    中銀活期寶貨幣

    0.6842

    0.02624

    2019-04-15

    000996

    000996

    中銀新動力股票 0.583 0.583

    2019-04-15

    380009

    380009

    中銀添利債券

    中銀添利債券發起

    A 1.273 1.575

    005852

    中銀添利債券發起

    C 1.265 1.567

    007100

    中銀添利債券發起

    E 1.272 1.272

    1.3369

    0.02628

    2019-04-14

    002286

    002286

    中銀美元債(QDII)

    2019-04-12

    中銀美元債債券(QDII)人民幣份額1.11801.1180

    002287

    中銀美元債債券(QDII)美元份額

    0.16630.1663

    2019-04-12

    日期

    基金單位凈值(元)

    基金累計凈值(元)

    2019-04-15 003582 中金量化多策略

    1.090

    1.090

    2019-04-15 005860

    中金新豐A

    1.0170

    1.0170

    2019-04-15 005861

    中金新豐C

    1.0122

    1.0122

    2019-04-15 006279

    中金瑞祥A

    1.0794

    1.0794

    2019-04-15 006280

    中金瑞祥C

    0.9925

    0.9925

    賬套名稱

    產品代碼

    日期

    單位凈值

    累計凈值

    中加心享混合A

    002027

    2019-04-15

    1.0803

    1.1303

    中加心享混合C

    002533

    2019-04-15

    1.0816

    1.2827

    中加頤享純債債券

    004910

    2019-04-15

    1.0290

    1.0857

    中加頤合純債債券

    006180

    2019-04-15

    1.0021

    1.0211

    凈值情況

    圓信永豐雙紅利A

    000824

    1.222

    2.161

    圓信永豐雙紅利C

    000825

    1.199

    2.091

    圓信永豐優加生活股票型證券投資基金001736

    1.495

    1.495

    圓信永豐興利A

    001918

    1.070

    1.103

    圓信永豐興利C

    001919

    1.085

    1.111

    圓信永豐興融A

    002073

    1.018

    1.129

    圓信永豐興融C

    002074

    1.016

    1.119

    強化收益A類

    002932

    1.1381

    1.1381

    強化收益C類

    002933

    1.1262

    帳套名稱

    累計單位凈值

    003898

    3006-永贏豐益債券

    2019-4-15

    1.0246

    1.1033

    006094

    3016-永贏泰益債券

    其中:永贏泰益債券A

    2019-4-15

    1.0133

    1.0303

    006095

    其中:永贏泰益債券C

    2019-4-15

    1.0126

    1.0286

    006576

    3027-永贏誠益債券

    其中:永贏誠益債券A

    2019-4-15

    1.0015

    1.0120

    006577

    其中:永贏誠益債券C

    2019-4-15

    1.0007

    1.0108

    估值日期

    基金代碼 基金名稱

    份額凈值累計凈值

    2019-04-15

    001441 易方達瑞信混合I

    0.995

    001442 易方達瑞信混合E

    0.993

    005676 易方達標普消費品指數增強(QDII)C

    1.866

    118002 易方達標普消費品指數增強(QDII)A

    1.870

    110023 易方達醫療保健行業混合

    1.772

    161128 易方達標普信息科技指數證券投資基金(LOF) 1.4908 1.4908

    2019-04-15

    502010 易方達證券公司分級

    1.1396 -

    2019-04-15

    502011 易方達證券公司分級A

    1.0349 -

    2019-04-15

    502012 易方達證券公司分級B

    1.2443 -

    2019-04-15

    001382 易方達國企改革混合

    1.165

    003214 易方達富惠純債債券

    1.0254 1.1054

    2019-04-15

    005827 易方達藍籌精選混合型證券投資基金

    1.2262 1.2262

    2019-04-15

    110005 易方達積極成長混合

    0.6396 4.6535

    2019-04-15

    110012 易方達科匯靈活配置混合

    1.444

    5.868

    2019-04-15

    001342 易方達新享混合A

    1.672

    1.727

    2019-04-15

    001343 易方達新享混合C

    1.199

    1.254

    2019-04-15

    000603 易方達創新驅動混合

    0.887

    159950 易方達深證成指ETF

    1.0304 1.0304

    基金份額凈值

    基金份額累計凈值

    交易日期

    420005天弘周期策略混合型證券投資基金

    1.3190

    1.6900

    2019-04-

    15

    000962

    天弘中證500A

    0.9537

    0.9537

    005919

    天弘中證500C

    0.9755

    0.9755

    001552

    天弘中證證券保險A

    0.9147

    0.9147

    001553

    天弘中證證券保險C

    0.9062

    0.9062

    002388

    天弘裕利A

    1.1409

    1.1502

    005997

    天弘裕利C

    1.0346

    單位凈值(元)

    累計凈值(元)

    2019-04-15002245

    泰康穩健增利債券A

    1.1453

    1.1453

    2019-04-15002246

    泰康穩健增利債券C

    1.2659

    1.2659

    2019-04-15005523

    泰康頤年混合A

    1.0548

    1.0548

    2019-04-15005524

    泰康頤年混合C

    1.0506

    基金份額凈值/每基金份額累計凈(百、百萬)萬份基值/7日年化收益金已實現收益/份率/份額累計參考額參考凈值 凈值

    001009 上投摩根安全戰略股票型證券投資基金 2019-04-150.903

    0.903

    001126 上投摩根卓越制造股票型證券投資基金 2019-04-150.723

    0.723

    001192

    上投摩根整合驅動靈活配置混合型證券投資基金

    2019-04-150.572

    0.572

    001313 上投摩根智慧互聯股票型證券投資基金 2019-04-150.693

    0.693

    003243

    上投摩根中國世紀靈活配置混合型證券投資基金(QDII)

    2019-04-121.341

    1.341

    377020 上投摩根內需動力混合型證券投資基金 2019-04-150.7592

    1.5109

    份額凈值(元)累計凈值(元)

    001897九泰久盛量化混合A

    2019年4月15日

    1.000

    1.181

    004510九泰久盛量化混合C

    2019年4月15日 0.991

    1.172

    001782九泰久益混合A

    2019年4月15日

    1.336

    1.470

    001844九泰久益混合C

    2019年4月15日

    1.284

    1.418

    估值日期 基金代碼

    基金名稱

    基金單位凈值基金累計凈值

    2019-4-15410004

    華富債券A

    1.5627

    2.1957

    2019-4-15410005

    華富債券B

    1.5420

    2.1310

    2019-4-15000898

    華富恒穩純債A

    1.1980

    1.1980

    2019-4-15000899

    華富恒穩純債C

    1.1750

    1.1750

    2019-4-15003152

    華富天鑫靈活配置混合A

    0.8167

    0.8167

    2019-4-15003153

    華富天鑫靈活配置混合C

    0.8013

    份額凈值(元)

    累計凈值(元)

    006356國融穩融債券A

    2019年4月15日

    1.002

    1.002

    006357國融穩融債券C

    產品收益增長

    線(%)

    每萬份收益

    (元)

    七日年化收益率

    (%)

    00090

    2

    00090

    1

    國開泰富貨幣市場基金

    2.503

    0.6387

    2.257

    0.5729

    2.257

    378,879,026.04

    資產凈值(元)

    基金份額累計凈

    值(元)

    00529

    8

    00376

    3

    00464

    9

    國開泰富睿富債券型證券投資基金130,077,014.47

    1.0103

    1.0103

    國開開泰混合A 11,880,696.01

    1.0781

    1.1271

    國開開泰混合C215,409,414.74

    1.0672

    1.1162

    國開泰富開航靈活配置混合型發起式證券投資基金

    21,511,896.06

    0.9650

    分級代碼

    每百份基金已實現收益

    每萬份基金已實現收益

    每百萬份基金已實現收益

    7日年基金化收 份額益率 參考凈值

    基金份額累計參考凈值

    資產凈值

    估值日期

    4810048100工銀核心價值混 2019-

    1 1 合 04-15

    4810048100工銀核心價值混

    1 1 合A 0.291545076 2019-.04-15

    4810096001工銀核心價值混 2019-

    1 0 合H 04-15

    4810048100工銀大盤藍籌混 2019-

    8 8 合 1.1271.846 04-15

    0017100171工銀新焦點靈活 2019-

    5 5 配置混合 04-15

    0017100171工銀新焦點靈活 2019-

    5 5 配置混合A 1.0391.039 04-15

    0017100199工銀新焦點靈活

    5 8 配置混合C 1.0221.022 2019-04-15

    0002500025工銀金融地產混

    1 1 合 2.4853 2019-.22004-15

    0005200052工銀薪金寶貨幣 2019-

    8 8 04-14

    0005200052工銀薪金貨幣A 13693 0.0276 2019-

    8 8 . 1 04-14

    0005200071

    8 6 工銀薪金貨幣B 1.5063 0.0301 2019-904-14

    0005200052

    8 8 工銀薪金寶貨幣 2019-04-15

    0005200052工銀薪金貨幣A 07107 0.0266 2019-

    8 8 . 3 04-15

    0005200071

    8 6 工銀薪金貨幣B 07795 0.0292 2019-.104-15

    0026700267

    9 9 工銀安盈貨幣 2019-04-14

    0026700267

    9 9 工銀安盈貨幣A 1.2194 0.0222 2019-504-14

    0026700268

    9 0 工銀安盈貨幣B 13510 0.0246 2019-.404-14

    0026700267

    9 9 工銀安盈貨幣 2019-04-15

    0026700267工銀安盈貨幣A 06199 0.0223 2019-

    9 9 . 2 04-15

    0026700268 0.0247 2019-

    9 0 工銀安盈貨幣B 0.6857 1 04-15

    1648016480工銀四季收益債

    8 8 券 1.06081.6187 2019-04-15

    0006700067

    7 7 工銀現金貨幣 1.3572 0.0267 2019-504-14

    0006700067工銀現金貨幣 11552 0.0292 2019-

    7 7 . 3 04-15

    0023700237工銀香港中小盤 2019-

    9 9 股票(QDII) 1.2131.213 04-12

    0060000600工銀醫藥健康股 2019-

    2 2 票 04-15

    0060000600工銀醫藥健康股 2019-

    2 2 票A 1.21471.2147 04-15

    0060000600工銀醫藥健康股

    2 3 票C 1.20911.2091 2019-04-15

    0068300683工銀瑞信尊享短 2019-

    4 4 債債券 04-15

    0068300683工銀尊享短債債 2019-

    4 4 券A 1.00451.0045 04-15

    0068300683工銀尊享短債債 2019-

    4 5 券C 1.00361.0036 04-15

    節假日期間

    節假日期間萬份基金收

    節假日期間最后—日七日年化收益率(%)

    資產凈值

    托管人

    004865格林貨幣A

    2019-04-13至2019-04-14

    0.9169

    1.705

    0.00

    國泰君安證券股份有限公司

    004866格林貨幣B

    2019-04-13至2019-04-14

    1.0484

    1.951

    萬份基金收益

    004865

    格林貨幣A

    0.4670

    1.695

    國泰君安證券股份有

    限公司

    004866

    格林貨幣B

    0.5330

    1.940

    份額累計凈值

    托管人

    004942

    格林伯元靈活配置

    A

    0.9482

    0.9482

    興業銀行股份有限公司

    004943

    格林伯元靈活配置

    C

    0.9465

    006184

    格林泓鑫純債A

    1.0135

    1.0135

    中國工商銀行股份有

    限公司

    006185

    格林泓鑫純債C

    1.0134

    006181

    格林伯銳靈活配置

    A

    1.0102

    1.0102

    交通銀行股份有限公司

    006182

    1.0096

    賬套編號

    賬套名稱 基金名稱

    基金代碼

    基金單位凈值

    資產凈值

    萬份單7日年位基金化收益收益 率

    基金累計凈值

    節假日萬份單位基金收益

    節假日7日年化收益率

    估值表是否確認

    20194 800創金合信轉創金合信轉00210--

    15 6債精選債券債精選債券A1

    1.141

    7

    0.000.00000.000001.2154 0.00000.00000 是

    20194 800創金合信轉創金合信轉00210--

    15 6債精選債券債精選債券C2

    0.000.00000.000001.1146 0.00000.00000 是

    20194 800創金合信滬創金合信滬00231--

    157深300增強深300增強A0

    1.060

    2

    0.000.00000.000001.1982 0.00000.00000 是

    20194 800創金合信滬創金合信滬00231--

    157深300增強深300增強C5

    1.062

    2

    0.000.00000.000001.2072 0.00000.00000 是

    20194 800創金合信中創金合信中00231--

    15 8證500增強證500增強A1

    1.016

    0

    0.000.00000.000001.0160 0.00000.00000 是

    20194 800創金合信中創金合信中00231--

    15 8證500增強證500增強C6

    1.019

    9

    0.000.00000.000001.0199 0.00000.00000 是

    20194 801創金合信尊創金合信尊00233--

    15 4享純債債券享純債債券6

    1.0880.000.00000.00000

    1.114 0.00000.00000 是

    2019801創金合信金創金合信金

    -4-9融地產精選融地產精選00323

    15 股票 股票A 2

    0.967

    1

    0.000.00000.000001.0494 0.00000.00000 是

    15 股票 股票C 3

    0.964

    6

    0.000.00000.000001.0567 0.00000.00000 是

    20194 802創金合信尊創金合信尊00328--

    15 2泰純債債券泰純債債券9

    0.000.00000.000001.0012 0.00000.00000 是

    20194 802創金合信量創金合信量00435--

    15 9化核心混合化核心混合A9

    1.127

    5

    0.000.00000.000001.1775 0.00000.00000 是

    20194 802創金合信量創金合信量00436--

    15 9化核心混合化核心混合C0

    1.104

    0

    0.000.00000.000001.1540 0.00000.00000 是

    2019

    4 803創金合信尊創金合信尊00319--

    15 0智純債 智純債 3

    1.040

    0

    0.000.00000.000001.0790 0.00000.00000 是

    20194 803創金合信科創金合信科00549--

    153技成長 技成長股票A5

    0.942

    2

    0.000.00000.000000.9422 0.00000.00000 是

    20194 803創金合信科創金合信科00549--

    153技成長 技成長股票C6

    0.936

    2

    0.000.00000.000000.9362 0.00000.00000 是

    20194 803創金合信價創金合信價00246--

    15 9值紅利混合值紅利混合A3

    1.021

    4

    0.000.00000.000001.0214 0.00000.00000 是

    20194 803創金合信價創金合信價00540--

    15 9值紅利混合值紅利混合C4

    1.007

    8

    0.000.00000.000001.0078 0.00000.00000 是

    名稱

    代碼

    財通資管鑫銳混合A

    004900

    2019-4-15

    1.0198

    1.0198

    財通資管鑫銳混合C

    004901

    2019-4-15

    1.0151

    信誠幸福消費股票

    000551

    1.8250

    1.8250

    信誠惠澤債券型證券投資基金

    165530

    1.0251

    1.1181

    信誠多策略靈活配置

    165531

    0.9090

    0.9175

    信誠滬深300指數分級

    165515

    0.903

    1.568

    信誠滬深300指數分級A

    150051

    1.015

    1.384

    信誠滬深300指數分級B

    150052

    0.791

    1.490

    信誠三得益債券A

    550004

    1.138

    1.634

    信誠三得益債券B

    550005

    1.109

    1.576

    信誠中證基建工程指數分級

    165525

    0.921

    0.929

    信誠景瑞A

    003614

    1.0538

    1.1098

    信誠景瑞C

    003615

    1.0502

    1.1062

    005226

    山證改革精選

    0.9203

    金元順安元啟靈活配置混合型證券投資基金

    004685

    1.0979

    單位凈值 累計凈值

    1.0930 1.0930

    金元順安桉盛債券型證券投資基金

    004093

    每萬份基金收

    基金七日收益率(日結轉份額)

    金元順安金通寶貨幣市場基金

    004072-總層面

    1.00001.0000

    0.6692

    2.419%

    金通寶貨幣A類

    004072

    1.00001.0000

    0.6035

    2.174%

    金通寶貨幣B類

    004073

    1.00001.0000

    0.6693

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有