在網(wǎng)上如何找做網(wǎng)站的人品牌營銷策略分析
21.1 攻克難題——字符串顯示API
顯示單個(gè)字符時(shí),用 [CS:ECX] 的方式特意指定了 CS(代碼段寄存器),因此可以成功讀取 msg的內(nèi)容。但在顯示字符串時(shí),由于無法指定段地址,程序誤以為是 DS而從完全錯(cuò)誤的內(nèi)存地址中讀取了內(nèi)容。hrb_api并不知道代碼段的起始位置位于內(nèi)存的哪個(gè)地址,但cmd_app應(yīng)該知道,因?yàn)楫?dāng)初設(shè)置這個(gè)代碼段的正是cmd_app。
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){(中略)if (finfo != 0) {/* 找到了與字符串相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);
/*這里*/ *((int *) 0xfe8) = (int) p;file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);farcall(0, 1003 * 8);memman_free_4k(memman, (int) p, finfo->size);cons_newline(cons);return 1;}return 0;
}//根據(jù)輸入?yún)?shù)打印數(shù)據(jù) eax為當(dāng)前字符 ebx為字符串 ecx長度
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax){
/*這里*/int cs_base = *((int *) 0xfe8);struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);if(edx == 1)cons_putchar(cons, eax&0xff, 1);else if(edx == 2)
/*這里*/cons_putstr0(cons, (char*)ebx+cs_base);else if(edx == 3)
/*這里*/cons_putstr1(cons, (char*)ebx+cs_base, ecx);return;
}
21.2 用C語言編寫應(yīng)用程序
按照之前章節(jié)的理解,都是從匯編程序中輸入了提前設(shè)定的字符才能進(jìn)行打印,若將其整合成一個(gè)函數(shù),當(dāng)調(diào)用該函數(shù)時(shí),便可打印豈不是更方便?函數(shù)api_putchar就是將輸入?yún)?shù)c寫入寄存器,并調(diào)用INT 0x40,該中斷執(zhí)行文件console.c中的hrb_api函數(shù)進(jìn)行字符打印(詳情看20.6節(jié))。
按照文件分工,hello3.c文件調(diào)用了a_nask.nas文件中的函數(shù),需要在Makefile文件中添加如下代碼(文件格式請參考30天自制操作系統(tǒng)(第1-3天)中的2.6節(jié)):
hello3.bim : hello3.obj a_nask.obj Makefile
?? ?$(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj
hello3.hrb : hello3.bim Makefile
?? ?$(BIM2HRB) hello3.bim hello3.hrb 0
/* hello3.c */
void api_putchar(int c);void HariMain(void)
{api_putchar('h');api_putchar('e');api_putchar('l');api_putchar('l');api_putchar('o');return;
}/* a_nask.nas */
_api_putchar: ; void api_putchar(int c);MOV EDX,1MOV AL,[ESP+4] ; cINT 0x40RET
21.3 保護(hù)操作系統(tǒng)(1)
需要為應(yīng)用程序提供專用的內(nèi)存空間,并且告訴它們 “ 別的地方不許碰哦 ”。要做到這一點(diǎn),可以創(chuàng)建應(yīng)用程序?qū)S玫臄?shù)據(jù)段,并在應(yīng)用程序運(yùn)行期間,將 DS 和 SS 指向該段地址。
? 操作系統(tǒng)用代碼段 ……2 * 8
? 操作系統(tǒng)用數(shù)據(jù)段 ……1 * 8
? 應(yīng)用程序用代碼段 ……1003 * 8
? 應(yīng)用程序用數(shù)據(jù)段 ……1004 * 8
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){(中略)char name[18], *p, *q;(中略)if (finfo != 0) {/* 找到了與字符串相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);
/*這里*/q = (char *) memman_alloc_4k(memman, 64*1024);*((int *) 0xfe8) = (int) p;file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
/*這里*/set_segmdesc(gdt + 1004, 64*1024 - 1, (int) q, AR_DATA32_RW);(中略)
/*這里*/start_app(0, 1003 * 8, 64 * 1024, 1004 * 8);memman_free_4k(memman, (int) p, finfo->size);
/*這里*/memman_free_4k(memman, (int) q, 64*1024);cons_newline(cons);return 1;}return 0;
}
;void start_app(int eip, int cs, int esp, int ds);
;操作系統(tǒng)棧的ESP保存在0xfe4這個(gè)地址,以便從應(yīng)用程序返回操作系統(tǒng)時(shí)使用
_start_app:PUSHAD ;將8個(gè)32位寄存器壓入棧,即8*(32/8)=32字節(jié)MOV EAX,[ESP+36] ; 應(yīng)用程序用EIPMOV ECX,[ESP+40] ; 應(yīng)用程序用CSMOV EDX,[ESP+44] ; 應(yīng)用程序用ESPMOV EBX,[ESP+48] ; 應(yīng)用程序用DS/SSMOV [0xfe4],ESP ; 操作系統(tǒng)用ESPCLI ; 在切換過程中禁止中斷請求MOV ES,BXMOV SS,BXMOV DS,BXMOV FS,BXMOV GS,BXMOV ESP,EDX ; ESP為應(yīng)用程序STI ; 切換完成后恢復(fù)中斷請求PUSH ECX ; 用于far-CALL的PUSH(cs=1003*8)PUSH EAX ; 用于far-CALL的PUSH(eip=0)CALL FAR [ESP] ; 調(diào)用應(yīng)用程序
; 應(yīng)用程序結(jié)束后返回此處MOV EAX,1*8 ; 操作系統(tǒng)用DS/SSCLI ; 再次進(jìn)行切換,禁止中斷請求MOV ES,AXMOV SS,AXMOV DS,AXMOV FS,AXMOV GS,AXMOV ESP,[0xfe4] ; 切換成操作系統(tǒng)ESPSTI ; 切換完成后恢復(fù)中斷請求POPAD ; 恢復(fù)之前保存的寄存器值RET
21.4 對異常的支持
要想強(qiáng)制結(jié)束程序,只要在中斷號 0x0d 中注冊一個(gè)函數(shù)即可,這是因?yàn)樵趚86架構(gòu)規(guī)范中,當(dāng)應(yīng)用程序試圖破壞操作系統(tǒng),或者試圖違背操作系統(tǒng)的設(shè)置時(shí),就會自動產(chǎn)生 0x0d 中斷,因此該中斷也被稱為 “ 異?!?。寫一個(gè)與 _asm_inthandler20函數(shù)大同小異的_asm_inthandler0d函數(shù),與_asm_inthandler20的主要區(qū)別在于增加了STI/CLI這樣控制中斷請求禁止、恢復(fù)的指令和根據(jù)inthandler0d的結(jié)果來執(zhí)行強(qiáng)制結(jié)束應(yīng)用程序的操作 。
_asm_inthandler0d:STIPUSH ESPUSH DSPUSHADMOV AX,SSCMP AX,1*8JNE .from_app; 當(dāng)操作系統(tǒng)活動時(shí)產(chǎn)生中斷的情況和之前差不多MOV EAX,ESPPUSH SS ; 保存中斷時(shí)的SSPUSH EAX ; 保存中斷時(shí)的ESPMOV AX,SSMOV DS,AXMOV ES,AXCALL _inthandler0dADD ESP,8POPADPOP DSPOP ESADD ESP,4 ; 在INT 0x0d中需要這句IRETD
.from_app:; 當(dāng)應(yīng)用程序活動時(shí)產(chǎn)生中斷CLIMOV EAX,1*8MOV DS,AX ; 先僅將DS設(shè)定為操作系統(tǒng)用MOV ECX,[0xfe4] ; 操作系統(tǒng)的ESPADD ECX,-8MOV [ECX+4],SS ; 保存產(chǎn)生中斷時(shí)的SSMOV [ECX ],ESP ; 保存產(chǎn)生中斷時(shí)的ESPMOV SS,AXMOV ES,AXMOV ESP,ECXSTICALL _inthandler0dCLICMP EAX,0JNE .killPOP ECXPOP EAXMOV SS,AX ; 將SS恢復(fù)為應(yīng)用程序用MOV ESP,ECX ; 將ESP恢復(fù)為應(yīng)用程序用POPADPOP DSPOP ESADD ESP,4 ; INT 0x0d需要這句IRETD
.kill:; 將應(yīng)用程序強(qiáng)制結(jié)束MOV EAX,1*8 ; 操作系統(tǒng)用的DS/SSMOV ES,AXMOV SS,AXMOV DS,AXMOV FS,AXMOV GS,AXMOV ESP,[0xfe4] ; 強(qiáng)制返回到start_app時(shí)的ESPSTI ; 切換完成后恢復(fù)中斷請求POPAD ; 恢復(fù)事先保存的寄存器值RET