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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm)

發布時間:2023/12/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

源程序來源

加載程序

c08_mbr.asm

用戶源程序:增加注釋

;

;文件名:c08-2.asm

;文件說明:用戶程序

;創建日期:13:08 2018/5/23

;----------------------------------------------------------------------

SECTION header vstart=0 ;定義用戶程序頭部段

program_length dd program_end ;程序總長度[0x00]

;用戶程序入口點

code_entry dw start ;偏移地址[0x04] 此處的start來源于自己的命名

dd section.code_1.start ;段地址[0x06] 此處.start是匯編指令的語法

realloc_tbl_len dw (header_end - code_1_segment)/4

;段重定位表項個數[0x0a]

;1個表項占4個字節

;段重定位表項

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 ;定義代碼段1(16字節對齊)

put_string: ;顯示串(字符串以0結尾)

mov cl,[bx] ;取一個字符

or cl,cl ;cl=0?

jz .exit ;cl=0時返回主程序

call put_char

inc bx ;下一個字符

jmp put_string

.exit:

ret

;----------------------------------------------------------------------

put_char: ;顯示一個字符

push ax

push bx

push cx

push dx

push ds

push es

;以下取當前光標:光標位置是一個16位的數值

mov dx,0x3d4 ;索引寄存器端口號 0x3d4

mov al,0x0e ;索引值14

out dx,al

mov dx,0x3d5 ;數據端口0x3d5

in al,dx ;高8位

mov ah,al

mov dx,0x3d4

mov al,0x0f

out dx,al

mov dx,0x3d5

in al,dx ;低8位

mov bx,ax ;BX 存放代表光標位置的16位數

cmp cl,0x0d ;回車符?

jnz .put_0a ;不是回車,看看是不是換行等字符?

mov ax,bx

mov bl,80

div bl

mul bl

mov bx,ax

jmp .set_cursor

.put_0a:

cmp cl,0x0a ;換行符?

jnz .put_other ;不是換行符,則正常顯示字符

add bx,80

jmp .roll_screen

.put_other:

mov ax,0xb800

mov es,ax

shl bx,1 ;左移1位相當于乘以2

mov [es:bx],cl ;于光標處顯示字符

;以下將光標位置推進一個字符

shr bx,1 ;右移相當于除以2,換回來bx

add bx,1 ;推進光標位置

.roll_screen: ;VGA文本模式,每行80個字符,25行

cmp bx,2000 ;光標超出屏幕?滾屏

jl .set_cursor

mov ax,0xb800

mov ds,ax

mov es,ax

cld

mov si,0xa0 ;從屏幕第2行第0列開始向上復制一行

mov di,0x00

mov cx,1920 ;80*25-80=1920

rep movsw ;以字為單位進行復制

mov bx,3840 ;4000 - 160 = 3840 清楚屏幕最底一行

mov cx,80 ;

.cls:

mov word [es:bx],0x0720 ;黑底白字的空格

add bx,2

loop .cls

mov bx,1920 ;光標位置是最后一行行首

;設置光標

.set_cursor: ;不同的情況已用不同的方法將光標的新位置計算好

mov dx,0x3d4

mov al,0x0e ;高8位

out dx,al

mov dx,0x3d5

mov al,bh

out dx,al

mov dx,0x3d4

mov al,0x0f ;低8位

out dx,al

mov dx,0x3d5

mov al,bl

out dx,al

pop es

pop ds

pop dx

pop cx

pop bx

pop ax

ret

;----------------------------------------------------------------------

start:

;初始化執行時,DS和ES指向用戶程序頭部段

mov ax,[stack_segment] ;設置到用戶程序到自己的堆棧

mov ss,ax

mov sp,stack_end ;stack段里保留保留256字節的空間 mov sp,256

mov ax,[data_1_segment] ;設置到用戶程序自己的數據段

mov ds,ax

mov bx,msg0 ;顯示第一段信息

call put_string ;put_string用[bx]取每一個字符

push word [es:code_2_segment] ;段寄存器DS切換到數據段2

mov ax,begin

push ax

retf ;轉移到代碼段2執行

continue:

mov ax,[es:data_2_segment] ;段寄存器DS切換到數據段2

mov ds,ax

mov bx,msg1

call put_string ;顯示第二段信息

jmp $

;----------------------------------------------------------------------

SECTION code_2 align=16 vstart=0 ;定義代碼段2(16字節對齊)

begin:

push word [es:code_1_segment]

mov ax,continue

push ax

retf ;轉移到代碼段1接著執行

;----------------------------------------------------------------------

SECTION data_1 align=16 vstart=0

msg0 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,0x0a

db ' Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a

db ' xor dx,dx',0x0d,0x0a

db ' xor ax,ax',0x0d,0x0a

db ' xor cx,cx',0x0d,0x0a

db ' @@:',0x0d,0x0a

db ' inc cx',0x0d,0x0a

db ' add ax,cx',0x0d,0x0a

db ' adc dx,0',0x0d,0x0a

db ' inc cx',0x0d,0x0a

db ' cmp cx,1000',0x0d,0x0a

db ' jle @@',0x0d,0x0a

db ' ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a

db 0

;----------------------------------------------------------------------

SECTION data_2 align=16 vstart=0

msg1 db ' The above contents is written by LeeChung. '

db '2011-05-06'

db 0

;----------------------------------------------------------------------

SECTION stack align=16 vstart=0

resb 256

stack_end:

;----------------------------------------------------------------------

SECTION trail align=16

program_end: ;trail段沒有vstart標記,program_end是針對用戶程序開頭的偏移量

代碼說明

循環與子程序的調用關系

循環

put_string

參數

DS 段寄存器器指向數據段

BX 指向字符串的標號所在(位于數據段內,vstart=0 規定是相對數據段開頭的偏移量)

-----------------------------------------------------------

-----------------------------------------------------------

子程序

put_char

功能

顯示一個字符(注意是一個)

參數

cl 要顯示的字符

過程

見下方put_char流程圖

-----------------------------------------------------------

-----------------------------------------------------------

光標位置的計算與光標的顯示分開的,由不同的情況計算出不同的位置數值,再統一由 子程序.setcursor 進行顯示。

圖8-19 過程put_char的流程圖.png

《x86匯編語言:從實模式到保護模式》 第143頁

光標的讀與寫

指定索引寄存器 端口號是 0x3d4

光標位置是16位數,索引值 14(0x0e)和 15(0x0f)提供光標位置的高8位、低8位

指定好寄存器之后,通過數據端口 0x3d5 進行讀寫

取光標位置,取到的位置16位數值放到 BX里面

===================================================

;以下取當前光標:光標位置是一個16位的數值

mov dx,0x3d4 ;索引寄存器端口號 0x3d4

mov al,0x0e ;索引值14

out dx,al

mov dx,0x3d5 ;數據端口0x3d5

in al,dx ;高8位

mov ah,al

mov dx,0x3d4

mov al,0x0f

out dx,al

mov dx,0x3d5

in al,dx ;低8位

mov bx,ax ;BX 存放代表光標位置的16位數

---------------------------------------------------------------------------------------------

寫光標位置,根據不同情況計算好的光標位置通過端口寫

===============================================================

;設置光標

.set_cursor: ;不同的情況已用不同的方法將光標的新位置計算好

mov dx,0x3d4

mov al,0x0e ;高8位

out dx,al

mov dx,0x3d5

mov al,bh

out dx,al

mov dx,0x3d4

mov al,0x0f ;低8位

out dx,al

mov dx,0x3d5

mov al,bl

out dx,al

-------------------------------------------------------------------------------------------------------------------

顯存、光標、字符

VGA 文本模式 一頁有25行,每行有80個字符

指定 es = 0xb800 di= 0x0000

假設要在第0行第0列,顯示一個字符‘a’

1、需要在偶數地址寫字符

mov es:[di],'a'

2、在奇數地址寫顏色屬性,黑底白字0x07

mov es:[di+1],0x07

因此可以看到一頁能顯示 80*25=2000個字符,

但同時也是存了4000個字節的數據

(一半是字符的ASCII碼,一半是每個字符的對應屬性)

光標的位置是一個16位的數值,

因此,對光標而言,

0表示第0行0列,

1表示第0行1列,

....

20表示第0行20列,

每一行有80列,

79表示第0行79列,

80表示第1行第0行(換行...)

....

==========================================

在子程序

.put_other:

mov ax,0xb800

mov es,ax

shl bx,1 ;左移1位相當于乘以2

mov [es:bx],cl ;于光標處顯示字符

;以下將光標位置推進一個字符

shr bx,1 ;右移相當于除以2,換回來bx

add bx,1 ;推進光標位置

是通過 光標的位置數值 來確定 字符的顯示位置的,

光標在哪里閃爍,字符就寫到那里,

【光標位置數值 x 2 = 字符要被送入的那個偶地址】

字符的顏色屬性默認是0x07不需要修改。

SECTION關鍵詞

在用戶程序中使用SECTION關鍵詞人為的分了很多段,然后把這些段集中放到頭部段header,并且借由加載器的回寫在執行時變成了都是可以映射到真實物理地址的段地址,需要用到哪個段就去頭部段里取,這樣少得可憐的段寄存器就夠用了,如果全局固定es指向頭部段,那么就瘋狂復用ds寄存器。

總結

以上是生活随笔為你收集整理的c汇编语言程序框架培训,[010][x86汇编语言]学习用户程序的编写(c08.asm)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。