1. 程式人生 > 實用技巧 >web 頁面滾動條的顯示與美化(只考慮Chrome)

web 頁面滾動條的顯示與美化(只考慮Chrome)

一、實驗目的

1. 理解80×25彩色字元模式顯示原理 2. 理解轉移指令jmp, loop, jcxz的跳轉原理,掌握使用其實現分支和迴圈的用法 3. 理解轉移指令call, ret, retf的跳轉原理,掌握組合使用call和ret/retf編寫彙編子程式的方法,掌握 引數傳遞方式 4. 理解標誌暫存器的作用 5. 理解條件轉移指令je, jz, ja, jb, jg, jl等的跳轉原理,掌握組合使用匯編指令cmp和條件轉移指令實 現分支和迴圈的用法 6. 瞭解在visual studio/Xcode等環境或利用gcc命令列引數反彙編c語言程式的方法,理解編譯器生成 的反彙編程式碼 7. 綜合應用定址方式和彙編指令完成應用程式設計

二、實驗準備

實驗前,請複習/學習教材以下內容: 第9章 轉移指令的原理 第10章 call和ret指令 第11章 標誌暫存器

三、實驗內容

1. 實驗任務1

教材「實驗9 根據材料程式設計」(P187-189) 程式設計:在螢幕中間分別顯示綠色、綠底紅色、白底藍色的字串'welcome to masm!'。
codesg ends
end start

assume cs:code, ds:data,ss:stack
data segment
        db 'Welcome to masm!'
        db 00000010b,00100100b,01110001b
data ends
stack segment
        db 
16 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov ax,16 mov sp,ax mov ax,0b800H mov ds,ax mov ax,data mov es,ax mov bx,1830 //第一行W所在的偏移地址 mov di,0 //記錄這是第幾行 mov cx,3 //外層迴圈次數 s0: push cx mov si,
0 mov cx,16 //記憶體迴圈次數,16為字串長度 s: mov al,es:[si] //取出一個字母,放在低位 mov ah,es:[di+16] //取出該i行的顏色資訊,放在高位 mov ds:[bx],ax //存入對應位置的視訊記憶體 inc si add bx,2 loop s pop cx add bx,0080h //一行是160個,按照道理應該是加上00a0h,但是在上面的迴圈裡面bx增加了32,所以這裡只用增加0080h inc di loop s0 mov ah, 4ch int 21h code ends end start

結果:

2. 實驗任務2

編寫子程式printStr,實現以指定顏色在螢幕上輸出字串。呼叫它,完成字串輸出。
assume cs:code, ds:data
data segment
    str db 'try', 0
data ends

code segment
start:  
    mov ax, data
    mov ds, ax

    mov si, offset str //用offset找到str標記的偏移地址
    mov al, 2
    call printStr      //呼叫子程式

    mov ah, 4ch
    int 21h

printStr:
    push bx
    push cx
    push si
    push di            //儲存暫存器

    mov bx, 0b800H     //視訊記憶體的段地址
    mov es, bx
    mov di, 0
s:  mov cl, [si]
    mov ch, 0
    jcxz over          //如果cl為0,就表示字串讀取結束,那麼cx為0,用jcxz跳出迴圈
    mov ch, al         //賦值顏色
    mov es:[di], cx
    inc si
    add di, 2
    jmp s

over:
pop di pop si pop cx pop bx ret code ends end start

彙編,執行程式碼,得到結果:

把line3改為:
str db 'another try', 0

這裡只是將字串改變,但是使用jcxz是當判斷後面出現0才結束寫入的迴圈,所以改變了顯示的個數。

把line12改為:
mov al, 4

4為00000100b,所以是黑底紅色,結果如下

line19-22, line36-39,這組對稱使用的push、pop,這樣用的目的是什麼? 用於保護和恢復暫存器的值,更好的利用暫存器 line30的功能是什麼? 將高位是顏色資訊,低位是字元ASCLL資訊的cx,存入視訊記憶體。

3. 實驗任務3

使用任意文字編輯器,錄入彙編源程式task3.asm。
assume cs:code, ds:data
data segment
        x dw 1984
        str db 16 dup(0)
data ends

code segment
start:  
        mov ax, data
        mov ds, ax
        mov ax, x           //將1984存入ax當被除數  07C0H=1984
        mov di, offset str
        call num2str

        mov ah, 4ch
        int 21h

num2str:
        push ax
        push bx
        push cx
        push dx         //儲存暫存器
        
        mov cx, 0
        mov bl, 10      //賦值除數
s1:      
        div bl          //除法運算
        inc cx
        mov dl, ah      //取出餘數
        push dx         //餘數進棧
        mov ah, 0       //餘數賦值0    因為這之前已經除過一次10了,而al能表示的最大數為255,所以這個程式碼能表示的範圍是0-2599
        cmp al, 0       //如果商為0,表示你將數字全部單個取出入棧了,那麼jne判斷不成功就會執行下面的程式碼,而不會繼續s1的迴圈了
        jne s1
s2:        
        pop dx
        or dl, 30h      //將數字轉化成字元
        mov [di], dl    //存入資料(字元)
        inc di
        loop s2
        
        pop dx          //還原暫存器
        pop cx
        pop bx
        pop ax

        ret
code ends
end start
對task3.asm進行彙編、連結,得到可執行程式後,在debug中使用u命令反彙編,使用g命令執行到line15(程式退出之前),使用d命令檢視資料段內容

查看出來的結果確實是1984的ASCLL值

對task3.asm原始碼進行修改、完善,把task2.asm中用於輸出以0結尾的字串的子程式加進來,實現對轉換後的字串進行輸出。
assume cs:code, ds:data
data segment
        x dw 2020
        str db 16 dup(0)
data ends

code segment
start:  
        mov ax, data
        mov ds, ax
        mov ax, x
        mov di, offset str
        call num2str
        mov si, offset str
        call  shuchu

        mov ah, 4ch
        int 21h

num2str:
        push ax
        push bx
        push cx
        push dx
        
        mov bx,0b800h
        mov es,bx
        mov cx, 0
        mov bl, 10
s1:      
        div bl
        inc cx
        mov dl, ah
        push dx
        mov ah, 0
        cmp al, 0
        jne s1
s2:        
        pop dx
        or dl, 30h
        mov [di], dl
        inc di
        loop s2
        
        pop dx
        pop cx
        pop bx
        pop ax

        ret
shuchu :
        push ax
        push bx
        push cx
        push dx
        
        mov bx, 0b800H
        mov es, bx
        mov di, 0
        mov al,2        //指定輸出的是綠色黑底
s:     
        mov cl, [si]
        mov ch, 0
        jcxz over
        mov ch, al
        mov es:[di], cx
        inc si
        add di, 2
        jmp s

over:        
        pop di
        pop si
        pop cx
        pop bx
        ret
code ends
end start
結果:

上面是我指定了al為2的情況
如果不指定,在呼叫了轉換成字元的子程式後,pop ax,將ax賦值成所輸入的數字,那麼此時的字元的顏色會隨著輸入的數字的變化而變化。

4. 實驗任務4

使用任意文字編輯器,錄入彙編源程式task4.asm。
assume cs:code, ds:data
data segment
        str db 80 dup(?)
data ends

code segment
start:  
        mov ax, data
        mov ds, ax
        mov si, 0

s1:        
        mov ah, 1
        int 21h         //讀取一個字元,放到ah中
        mov [si], al
        cmp al, '#'      //如果輸入的是#,那麼停止輸入,轉跳到下面的迴圈輸出語句,如果不是#,那麼跳回s1進行輸入
        je next          //使用的是ZF暫存器
        inc si
        jmp s1
next:
        mov cx, si
        mov si, 0
s2:     mov ah, 2
        mov dl, [si]
        int 21h      //輸出
        inc si
        loop s2

        mov ah, 4ch
        int 21h
code ends
end start
彙編、連結、執行程式,輸入一個字串並以#結束 line12-19實現的功能是? 首先利用int 21h 的1號子功能讀取一個字元,判斷輸入的字元是否為#,如果是,就用中斷轉移指令直接專挑到next,如果不是就迴圈回去讀取字元並將其儲存在資料段裡.因為中斷轉移在inc si上面,所以接下來的迴圈不會輸出#. line21-27實現的功能是? 根據上面得到的 si(字元的長度)設定迴圈次數,然後利用int 21h 的2號子功能依次輸出儲存的字元.

5. 實驗任務5

在visual studio整合環境中,編寫一個簡單的包含有函式呼叫的c程式。程式碼如下:
#include <stdio.h>
int sum(int, int); 
int main() 
{ 
    int a = 2, b = 7, c;
    c = sum(a, b); 
    return 0; 
}
int sum(int x, int y)
{ 
    return (x + y); 
}

反彙編得到的結果:

首先進行初始化操作,進行變數宣告,反彙編就會為其生成一條 mov指令為其賦值。呼叫函式時,實參引數自右向左,先把資料存入暫存器,在把他們進棧(先將引數b 的值存入暫存器eax,再壓入堆疊,再將引數a 的值存入暫存器ecx,再壓入堆棧。

實現了實參賦值給形參,通過 call 指令呼叫函式sum。sum函式內同樣先初始化並分配棧空間,執行得到的結果儲存在eax暫存器內,呼叫ret指令返回。執行完畢,返回主函式main,再將eax值賦值給引數c。主調函式根據壓入堆疊的引數的數目 2 和引數大小,利用指令 add esp,8 將引數全部彈出。此時堆疊就恢復到其呼叫前的狀態。