日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

硬盘和显卡的访问与控制(三)(含多彩的Hello)——《x86汇编语言:从实模式到保护模式》读书笔记03

發(fā)布時(shí)間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 硬盘和显卡的访问与控制(三)(含多彩的Hello)——《x86汇编语言:从实模式到保护模式》读书笔记03 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一篇博文我們用了很大的篇幅說(shuō)了加載器,這一篇我們?cè)撜f(shuō)說(shuō)用戶(hù)程序了。
先看作者的源碼吧。

;代碼清單8-2;文件名:c08.asm;文件說(shuō)明:用戶(hù)程序 ;創(chuàng)建日期:2011-5-5 18:17;=============================================================================== SECTION header vstart=0 ;定義用戶(hù)程序頭部段 program_length dd program_end ;程序總長(zhǎng)度[0x00];用戶(hù)程序入口點(diǎn)code_entry dw start ;偏移地址[0x04]dd section.code_1.start ;段地址[0x06] realloc_tbl_len dw (header_end-code_1_segment)/4;段重定位表項(xiàng)個(gè)數(shù)[0x0a];段重定位表 code_1_segment dd section.code_1.start ;[0x0c]code_2_segment dd section.code_2.start ;[0x10]data_1_segment dd section.data_1.start ;[0x14]data_2_segment dd section.data_2.start ;[0x18]stack_segment dd section.stack.start ;[0x1c]header_end: ;=============================================================================== SECTION code_1 align=16 vstart=0 ;定義代碼段116字節(jié)對(duì)齊) put_string: ;顯示串(0結(jié)尾)。;輸入:DS:BX=串地址mov cl,[bx]or cl,cl ;cl=0 ?jz .exit ;是的,返回主程序 call put_charinc bx ;下一個(gè)字符 jmp put_string.exit:ret;------------------------------------------------------------------------------- put_char: ;顯示一個(gè)字符;輸入:cl=字符asciipush axpush bxpush cxpush dxpush dspush es;以下取當(dāng)前光標(biāo)位置mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5in al,dx ;高8位 mov ah,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5in al,dx ;低8位 mov bx,ax ;BX=代表光標(biāo)位置的16位數(shù)cmp cl,0x0d ;回車(chē)符?jnz .put_0a ;不是。看看是不是換行等字符 mov ax,bx ;此句略顯多余,但去掉后還得改書(shū),麻煩 mov bl,80 div blmul blmov bx,axjmp .set_cursor.put_0a:cmp cl,0x0a ;換行符?jnz .put_other ;不是,那就正常顯示字符 add bx,80jmp .roll_screen.put_other: ;正常顯示字符mov ax,0xb800mov es,axshl bx,1mov [es:bx],cl;以下將光標(biāo)位置推進(jìn)一個(gè)字符shr bx,1add bx,1.roll_screen:cmp bx,2000 ;光標(biāo)超出屏幕?滾屏jl .set_cursormov ax,0xb800mov ds,axmov es,axcldmov si,0xa0mov di,0x00mov cx,1920rep movswmov bx,3840 ;清除屏幕最底一行mov cx,80.cls:mov word[es:bx],0x0720 ; spaceadd bx,2loop .clsmov bx,1920.set_cursor:mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5mov al,bhout dx,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5mov al,blout dx,alpop espop dspop dxpop cxpop bxpop axret;---------------------------------- 用戶(hù)程序入口 --------------------------------------------start:;初始執(zhí)行時(shí),DS和ES指向用戶(hù)程序頭部段mov ax,[stack_segment] ;設(shè)置到用戶(hù)程序自己的堆棧 mov ss,axmov sp,stack_endmov ax,[data_1_segment] ;設(shè)置到用戶(hù)程序自己的數(shù)據(jù)段mov ds,axmov bx,msg0call put_string ;顯示第一段信息 push word [es:code_2_segment]mov ax,beginpush ax ;可以直接push begin,80386+retf ;轉(zhuǎn)移到代碼段2執(zhí)行 continue:mov ax,[es:data_2_segment] ;段寄存器DS切換到數(shù)據(jù)段2 mov ds,axmov bx,msg1call put_string ;顯示第二段信息 jmp $ ;=============================================================================== SECTION code_2 align=16 vstart=0 ;定義代碼段216字節(jié)對(duì)齊)begin:push word [es:code_1_segment]mov ax,continuepush ax ;可以直接push continue,80386+retf ;轉(zhuǎn)移到代碼段1接著執(zhí)行 ;=============================================================================== SECTION data_1 align=16 vstart=0msg0 db ' This is NASM - the famous Netwide Assembler. 'db 'Back at SourceForge and in intensive development! 'db 'Get the current versions from http://www.nasm.us/.'db 0x0d,0x0a,0x0d,0x0adb ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0adb ' xor dx,dx',0x0d,0x0adb ' xor ax,ax',0x0d,0x0adb ' xor cx,cx',0x0d,0x0adb ' @@:',0x0d,0x0adb ' inc cx',0x0d,0x0adb ' add ax,cx',0x0d,0x0adb ' adc dx,0',0x0d,0x0adb ' inc cx',0x0d,0x0adb ' cmp cx,1000',0x0d,0x0adb ' jle @@',0x0d,0x0adb ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0adb 0;=============================================================================== SECTION data_2 align=16 vstart=0msg1 db ' The above contents is written by LeeChung. 'db '2011-05-06'db 0;=============================================================================== SECTION stack align=16 vstart=0resb 256stack_end: ;=============================================================================== SECTION trail align=16program_end:

接下來(lái)我們分塊分析。

SECTION header vstart=0 ;定義用戶(hù)程序頭部段 program_length dd program_end ;程序總長(zhǎng)度[0x00];用戶(hù)程序入口點(diǎn)code_entry dw start ;偏移地址[0x04]dd section.code_1.start ;段地址[0x06] realloc_tbl_len dw (header_end-code_1_segment)/4;段重定位表項(xiàng)個(gè)數(shù)[0x0a];段重定位表 code_1_segment dd section.code_1.start ;[0x0c]code_2_segment dd section.code_2.start ;[0x10]data_1_segment dd section.data_1.start ;[0x14]data_2_segment dd section.data_2.start ;[0x18]stack_segment dd section.stack.start ;[0x1c]header_end:

這段代碼用來(lái)定義用戶(hù)程序的頭部。頭部格式在上一篇博文已經(jīng)說(shuō)過(guò)了。
因?yàn)闃?biāo)號(hào)program_end所在的段沒(méi)有指定vstart==XX,所以program_end的匯編地址就從程序開(kāi)頭(=0)開(kāi)始計(jì)算,它所代表的匯編地址就是整個(gè)程序的大小(以字節(jié)計(jì)算)。
每個(gè)段都有一個(gè)匯編地址,它是相對(duì)于整個(gè)程序開(kāi)頭(0)的,為了方便取得某個(gè)段的匯編地址,NASM編譯器提供了如下表達(dá)式:
section.段名稱(chēng).start

如圖所示:

因?yàn)槌绦虻娜肟邳c(diǎn)在code_1段中,所以是

dw start ;偏移地址[0x04]dd section.code_1.start ;段地址[0x06]

其他語(yǔ)句源碼中都有注釋,很好理解。

put_char: ;顯示一個(gè)字符;輸入:cl=字符ascii,ch=字符屬性push axpush bxpush cxpush dxpush dspush es;以下取當(dāng)前光標(biāo)位置mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5in al,dx ;高8位 mov ah,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5in al,dx ;低8位 mov bx,ax ;BX=代表光標(biāo)位置的16位數(shù)cmp cl,0x0d ;回車(chē)符?jnz .put_0a ;不是。看看是不是換行等字符 mov ax,bx ;此句略顯多余,但去掉后還得改書(shū),麻煩 mov bl,80 div blmul blmov bx,axjmp .set_cursor.put_0a:cmp cl,0x0a ;換行符?jnz .put_other ;不是,那就正常顯示字符 add bx,80jmp .roll_screen.put_other: ;正常顯示字符mov ax,0xb800mov es,axshl bx,1mov [es:bx],clmov [es:bx+1],ch ;這句是我自己加的,我想讓字符屬性通過(guò)ch傳遞 ;以下將光標(biāo)位置推進(jìn)一個(gè)字符shr bx,1add bx,1.roll_screen:cmp bx,2000 ;光標(biāo)超出屏幕?滾屏jl .set_cursormov ax,0xb800mov ds,axmov es,axcldmov si,0xa0mov di,0x00mov cx,1920rep movswmov bx,3840 ;清除屏幕最底一行mov cx,80.cls:mov word[es:bx],0x0720 ; spaceadd bx,2loop .clsmov bx,1920.set_cursor:mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5mov al,bhout dx,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5mov al,blout dx,alpop espop dspop dxpop cxpop bxpop axret

以上這段代碼是為了在光標(biāo)位置處顯示一個(gè)字符,并推進(jìn)光標(biāo)到下一個(gè)字符,還考慮到了滾屏。這段代碼書(shū)中有詳細(xì)的講解,這里就不贅述了。
唯一需要說(shuō)明的是,我希望可以顯示不同顏色的字,所以在里面加了一句 mov [es:bx+1],ch; ch是字符屬性

put_string: ;顯示串(0結(jié)尾)。;輸入:DS:BX=串地址mov cl,[bx]or cl,cl ;cl=0 ?jz .exit ;是的,返回主程序 call put_charinc bx ;下一個(gè)字符 jmp put_string.exit:ret

這段代碼又是一個(gè)過(guò)程,里面調(diào)用了put_char,看來(lái)過(guò)程是可以嵌套的!
or cl,cl 這句指令不會(huì)影響到cl里面的值,但計(jì)算結(jié)果會(huì)影響標(biāo)志寄存器的某些位。如果ZF置位,說(shuō)明cl的內(nèi)容為0,也就是串結(jié)束標(biāo)志。

我們從程序入口處看,要強(qiáng)調(diào)的是,當(dāng)加載器把執(zhí)行權(quán)交給用戶(hù)程序的時(shí)候,DS和ES都指向用戶(hù)程序的頭部段,也就是指向用戶(hù)程序的最開(kāi)始。start:;初始執(zhí)行時(shí),DS和ES指向用戶(hù)程序頭部段mov ax,[stack_segment] ;設(shè)置到用戶(hù)程序自己的堆棧 mov ss,axmov sp,stack_end

mov ax,[stack_segment] ;這句指令是到段的重定位表中取修正后的SS段的段基址。

mov ax,[data_1_segment] ;設(shè)置到用戶(hù)程序自己的數(shù)據(jù)段mov ds,axmov bx,msg0call put_string ;顯示第一段信息

從重定位表中獲得重定位之后data_1段的基址,賦值給ds,這樣之后,ds就不再指向用戶(hù)程序的頭部,而是指向data_1段。

push word [es:code_2_segment]mov ax,beginpush ax ;可以直接push begin,80386+retf ;轉(zhuǎn)移到代碼段2執(zhí)行

這段代碼用段超越前綴 es:code_2_segment 訪(fǎng)問(wèn)重定位表,把code_2段的基地址壓棧。(因?yàn)榇藭r(shí)ds已經(jīng)不再指向用戶(hù)頭部了,但是es還是指向用戶(hù)頭部);然后再把code_2段內(nèi)的一個(gè)標(biāo)號(hào)begin(代表偏移地址)也壓棧。
cpu執(zhí)行retf指令時(shí),相當(dāng)于執(zhí)行
pop ip
pop cs
這樣,執(zhí)行retf的時(shí)候,程序就相當(dāng)于轉(zhuǎn)移了,轉(zhuǎn)移到代碼段2執(zhí)行。

;====================================================== SECTION code_2 align=16 vstart=0 ;定義代碼段216字節(jié)對(duì)齊)begin:push word [es:code_1_segment]mov ax,continuepush ax ;可以直接push continue,80386+retf ;轉(zhuǎn)移到代碼段1接著執(zhí)行

代碼段2其實(shí)什么也沒(méi)有干,干的事情就是轉(zhuǎn)移到代碼段1的continue處,原理和上面一樣。
于是開(kāi)始執(zhí)行:

continue:mov ax,[es:data_2_segment] ;段寄存器DS切換到數(shù)據(jù)段2 mov ds,axmov bx,msg1call put_string ;顯示第二段信息 jmp $

這段代碼就是調(diào)用過(guò)程,顯示信息。

好了,下面我們可以把代碼修改一下,顯示自己想要的東西。
比如在顯示字符串前,給ch賦值,0X02表示綠色,0X04表示紅色。

我們也可以自定義要顯示的字符。
我修改后的用戶(hù)代碼如下:

;代碼清單8-2;文件名:c08.asm;文件說(shuō)明:用戶(hù)程序 ;創(chuàng)建日期:2011-5-5 18:17;=============================================================================== SECTION header vstart=0 ;定義用戶(hù)程序頭部段 program_length dd program_end ;程序總長(zhǎng)度[0x00];用戶(hù)程序入口點(diǎn)code_entry dw start ;偏移地址[0x04]dd section.code_1.start ;段地址[0x06] realloc_tbl_len dw (header_end-code_1_segment)/4;段重定位表項(xiàng)個(gè)數(shù)[0x0a];段重定位表 code_1_segment dd section.code_1.start ;[0x0c]code_2_segment dd section.code_2.start ;[0x10]data_1_segment dd section.data_1.start ;[0x14]data_2_segment dd section.data_2.start ;[0x18]stack_segment dd section.stack.start ;[0x1c]header_end: ;=============================================================================== SECTION code_1 align=16 vstart=0 ;定義代碼段116字節(jié)對(duì)齊) put_string: ;顯示串(0結(jié)尾)。;輸入:DS:BX=串地址;ch:屬性mov cl,[bx] or cl,cl ;cl=0 ?jz .exit ;是的,返回主程序 call put_charinc bx ;下一個(gè)字符 jmp put_string.exit:ret;------------------------------------------------------------------------------- put_char: ;顯示一個(gè)字符;輸入:cl=字符asciipush axpush bxpush cxpush dxpush dspush es;以下取當(dāng)前光標(biāo)位置mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5in al,dx ;高8位 mov ah,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5in al,dx ;低8位 mov bx,ax ;BX=代表光標(biāo)位置的16位數(shù)cmp cl,0x0d ;回車(chē)符?jnz .put_0a ;不是。看看是不是換行等字符 mov ax,bx ;此句略顯多余,但去掉后還得改書(shū),麻煩 mov bl,80 div blmul blmov bx,axjmp .set_cursor.put_0a:cmp cl,0x0a ;換行符?jnz .put_other ;不是,那就正常顯示字符 add bx,80jmp .roll_screen.put_other: ;正常顯示字符mov ax,0xb800mov es,axshl bx,1mov [es:bx],clmov [es:bx+1],ch;以下將光標(biāo)位置推進(jìn)一個(gè)字符shr bx,1add bx,1.roll_screen:cmp bx,2000 ;光標(biāo)超出屏幕?滾屏jl .set_cursormov ax,0xb800mov ds,axmov es,axcldmov si,0xa0mov di,0x00mov cx,1920rep movswmov bx,3840 ;清除屏幕最底一行mov cx,80.cls:mov word[es:bx],0x0720 ; spaceadd bx,2loop .clsmov bx,1920.set_cursor:mov dx,0x3d4mov al,0x0eout dx,almov dx,0x3d5mov al,bhout dx,almov dx,0x3d4mov al,0x0fout dx,almov dx,0x3d5mov al,blout dx,alpop espop dspop dxpop cxpop bxpop axret;---------------------------------- 用戶(hù)程序入口 --------------------------------------------start:;初始執(zhí)行時(shí),DS和ES指向用戶(hù)程序頭部段mov ax,[stack_segment] ;設(shè)置到用戶(hù)程序自己的堆棧 mov ss,axmov sp,stack_endmov ax,[data_1_segment] ;設(shè)置到用戶(hù)程序自己的數(shù)據(jù)段mov ds,axmov bx,msg0mov ch,0x02 ;greencall put_string ;顯示第一段信息 push word [es:code_2_segment]mov ax,beginpush ax ;可以直接push begin,80386+retf ;轉(zhuǎn)移到代碼段2執(zhí)行 continue:mov ax,[es:data_2_segment] ;段寄存器DS切換到數(shù)據(jù)段2 mov ds,axmov bx,msg1mov ch,0x04 ;redcall put_string ;顯示第二段信息 ;這里我們顯示出多彩的Hellomov cx,128 ;循環(huán)次數(shù)mov ah,0 @1:push cxmov bx,msg2mov ch,ah call put_string ;顯示Hellopop cxinc ah ;屬性值增加1loop @1jmp $ ;=============================================================================== SECTION code_2 align=16 vstart=0 ;定義代碼段216字節(jié)對(duì)齊)begin:push word [es:code_1_segment]mov ax,continuepush ax ;可以直接push continue,80386+retf ;轉(zhuǎn)移到代碼段1接著執(zhí)行 ;=============================================================================== SECTION data_1 align=16 vstart=0msg0 db ' This is NASM - the famous Netwide Assembler. 'db 'Back at SourceForge and in intensive development! 'db 'Get the current versions from http://www.nasm.us/.'db 0x0d,0x0a,0x0d,0x0adb ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0adb ' xor dx,dx',0x0d,0x0adb ' xor ax,ax',0x0d,0x0adb ' xor cx,cx',0x0d,0x0adb ' @@:',0x0d,0x0adb ' inc cx',0x0d,0x0adb ' add ax,cx',0x0d,0x0adb ' adc dx,0',0x0d,0x0adb ' inc cx',0x0d,0x0adb ' cmp cx,1000',0x0d,0x0adb ' jle @@',0x0d,0x0adb ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0adb 0;=============================================================================== SECTION data_2 align=16 vstart=0msg1 db ' The above contents is written by LeeChung. 'db '2011-05-06'db 0x0d,0x0a,0x0d,0x0adb 0msg2 db 'Hello'db 0 ;=============================================================================== SECTION stack align=16 vstart=0times 256 db 0stack_end: ;=============================================================================== SECTION trail align=16program_end:

OK,看一下結(jié)果吧,這就是多彩的Hello

【the end 】

總結(jié)

以上是生活随笔為你收集整理的硬盘和显卡的访问与控制(三)(含多彩的Hello)——《x86汇编语言:从实模式到保护模式》读书笔记03的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。