16位匯編語言第二講系統調用原理,以及各個寄存器詳解
昨天已將簡單的寫了一下匯編代碼,並且執行了第一個顯示到屏幕的helloworld
問題?
helloworld怎么顯示出來了.
一丶顯卡,顯存的概念
1.顯示hello就要操作顯示器,這是非常原始的,那個時候的程序員,並沒有像現在的RGB(紅綠藍)這樣的三色真彩色,那個時候就是操作顯卡的,定義了一個標准
這個標准就是我們要往固定的地址寫入數據,就會顯示出來
具體流程
操作顯卡 -> 顯卡有自己的緩存 -> 把數據寫入到顯存中, - > 顯示數據 (顯示到屏幕上)
但是那個時候是沒有字的,所以就開始造字,那個時候就是把英文的26的英文字母做出來顏色都是一樣的
比如 我們造一個1,並且把它放到顯存中
0 0 1 0 0
0 0 1 0 0 把這個1看做是一個二維數組,把這塊數據放到顯存中就會顯示1了.
0 0 1 0 0
二丶鋸齒的概念
我們發現,很多游戲中都有一個選項,叫做坑鋸齒
其實鋸齒是因為,以前做 1的時候,顏色就是黑白的 這樣的字就有一點點的齒痕.看着不舒服,所以后邊,就用三色,把和一個字相同顏色的都放在一起
這樣看的字就很平滑,很好看.

可以看出,我寫了一個 1字,放大后旁邊的像素有藍色的,紅色的黃色的等等,而以前的就是黑色一種,所以看着很難看.
三丶系統調用原理
比如我們想顯示一個字符串,直接 "hello"雙引號包含起來,給操作系統即可.就會顯示了.
那么原理是什么.
第一講中,說了一個指令字典,里面有功能號 int 21代表我們要調用那一項,而硬件是提供了一個表格,調用的時候直接查表
這個表格是函數指針數組,直接調用即可.
例如

但是我們會想,操作系統會調用這第21項顯示數據,那么這個表可能是無限的大的嗎,而操作系統提供的api就要好幾萬個,怎么一個表夠用嗎
所以后面有了ah寄存器傳參,上面的圖可以改為

當然可能不用Switch這種低效率的語法,會做優化,但是原理就是這樣,硬件廠商只提供指令,就是說我cpu一定會調用int 21指定,找到數組中的第21項
而 這個表格則是操作系統提供的.
所以現在就知道,什么是 int 21,和為什么ah給9才能顯示字符串了吧.
四丶新的問題系統沒有啟動之前就會顯示字符串
我們有沒有發現,系統還沒有啟動之前,就會顯示一段字符串,這個字符串是通過主板的bios顯示的
bios是不依賴於系統的,優先於系統存在.
操作系統啟動之后也可以調用
在指令字典中

在中斷碼中會有說,調用int 多少,參數通過什么寄存器給.等等. 他和cpu的那種表是不一樣的,但是都存在於操作系統啟動之前.
五丶寄存器詳解
1.IP指令寄存器
IP寄存器,上一講說過,IP寄存器適合CS段寄存器一起使用的,IP是偏移(ip寄存器叫做指令寄存器) 他是表示通過cs段寄存器 + IP的偏移,來確定下一條指令執行的位置
比如我們有一段匯編代碼

下一條指令執行的執行的位置是0100 ip就等於0100,可以用p指令查看. 其實ip等於0100是代表ip的偏移是0100,用cs段寄存器 * 16 + ip的偏移,就等於實際物理地址(也就是下一條指定指令的位置)也就是 mov ax,1
p指令調試查看
第一次

第一指令位置的偏移是0103 也就是 mov bx,2會開始執行,下面一次類推(不懂段寄存器,下面細講)
2.Flag標志寄存器
標志寄存器的好的博客簡介連接 https://my.oschina.net/clownfish/blog/142328
上一講也說了flag標志寄存器釋放各種標志的, flag標志器是16位
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| OF | DF | IF | TF | SF | ZF | AF | PF | CF |
通常標志器是9個,常用的有6個,不常用的有三個,說下不常用的吧 DF IF TF,其余就是常用的了
CF 進位標志( Carry Flag) :
當我們做加法運算的時候,比如兩數相加 結果是否進位了
進位的時候,標志就是1,否則標志就是0,如果是加法運算,那么標志位1代表進位,如果為減法,那么標志為借位
比如 3AH + 7CH = B6H (h在匯編中代表前邊的數字是16進制) 沒有進位CF = 0
AAH + 7CH = (1) 26H,最高位進位了,CF = 1
ZF 零標志(Zero Flag):
表示你運算的結果為0,則ZF = 1,如果不為零則ZF = 0
例子:
3AH + 7CH = B6H,結果不為零,ZF = 0
84H + 7CH = (1) 00H,結果是0,因為進位了,那么CF = 1
SF 符號標志位(sign flag):
表示運算的結果,最高位為1,則SF為1,否則最高位不為1 SF = 0
3AH + 7CH = B6H,結果的最高位不為零,以為B看做二進制的則是 1 0 1 1 最高位是1所以 SF = 1
84H + 7CH = (1) 00H,結果是0,最高位是0
PF 奇偶標志位 (Parity Flag)
表示你運算的結果中,統計1出現的個數(二進制的統計)如果1的個數為零,或者偶數的時候,則PF = 1,奇數則是0
比如
3AH + 7CH = B6H, = 1011 0110 B(后綴B代表二進制的意思) 統計個數,出現了五個1則PF = 0;
OF 溢出標志位(OverFlow Flag)
若運算結果有溢出(或者結果不正確)則OF = 1,否則OF = 1
比如
3AH + 7CH = B6H 產生了溢出, OF = 1
AAH + 7CH = (1) 26H,進位了,但是沒有溢出,OF = 0
1.溢出
在8位表達的整數返回的時候 是+127 -> -128
在16位表達的范圍內是: +32767~ -32768
比如 3AH + 7CH = B6H,在八位范圍中 3A = 10進制的58 7C = 十進制的124
那么結果就是58 + 124 = 182,遠遠超過了128的范圍,所以產生了一出,並一方面
B6H的結果變成補碼,其值就是-74,顯然結果也是不正確的
2.溢出和進位的不同
溢出標志OF,和進位標志CF是不同的,
極為標志表示無符號數運算的記過是否超出范圍,其運算結果仍然正確
溢出標志表示有符號數的運算結果是否超出了范圍,運算的結果已經是不正確了.
3.如何運用溢出和進位
這個取決於程序員
當處理器對兩個操作數進行運算的時候,會按照無符號的數據求得結果(為什么是無符號,因為負數有補碼)
並且設置進位標志位CF,同事,根據是否超出有符號數的范圍設置一處標志OF,也就是說也會設置進位,也會設置溢出標志位,設置溢出標志位的原因是無符號數已經超過了范圍了.
利用那個標志取決於程序員自己決定
4.溢出的原理判斷
簡而言之就是 正數加正數等於正數,但是此時結果的二進制最高位為1(1是負數的意思)那么計算機就認為產生了一出
AF 輔助進位標志(Auxiliary Carry Flag)
輔助標志位主要表示的是低4個的進位或者借位,和CF不同,CF是八位產生進位和借位才會設置標志位
所以這個為輔助進位標志位
比如:
3AH + 7CH = B6H,低四位有進位,則AF = 1
DF 方向標志位(Direction Flag)
比如我們的SI 和DI 變址寄存器如果要memcpy的時候,內存會增加或者減少.
DF就是控制地址的變化的方向的
DF = 0,則存儲器地址自動增加
DF = 1,則存儲器的地址自動減少
匯編中的CLD指令,表示復位方向標志,讓其DF = 0,地址自動增加
匯編中的STD指令,表示置位方向標志,DF = 1,表示地址曾東減少.
IF 中斷允許標志(Interrupt - enable Flag)
官方語言: 用於控制外部可屏蔽中斷是否可以被處理器響應
自己理解的
比如鍵盤按下,怎么知道按下的,以前是無限循環,但是效率特別低,現在改成了鍵盤按下就會像CPU發送一個信號
CPU正在執行指令的時候,你按了一下鍵盤,會先放棄當前指令,去執行鍵盤發送過來的按鍵指令,但是如果我們一直按着鍵盤不放,是不是當前的指令就執行不了了,所以我們設置標志即可屏蔽當前發送過來的指令
匯編指令 CLI指令復位中斷標志IF = 0;
匯編指令 STI指令置為中斷標志: IF = 1
IF = 1,則代表我們可以允許中斷(也就是屏蔽指令)
IF = 0,則IF 禁止中斷
TF 陷阱標志(Trap Flag)
用於控制處理器進入單步操作方式(一般調試器才會用到)
TF = 0,處理器正常工作
TF = 1,處理器單步執行指令
利用這個標志,可以對程序進行逐條指令的調試.
這種逐條指令的調試程序的方法就是單步調試,
沒有匯編指令,如果設置,則用 位運算 | 上即可.
二丶段寄存器以及存儲器
1.存儲器和段寄存器
簡而言之
說的就是寄存器是cpu內部的內存
內存可以存放外部數據
硬盤可以存放外部數據,斷電后還會存在
2.數據的表達單位
二進制 bit 0 1 組成
字節 byte 8個bit位組成
字 word 16位 : 2個字節組成
雙字DWord 32位,兩個字組成
分為大端模式存儲,和端模式存儲
官方語言是 LSB,MSB等等.小尾方式,和大尾方式
大端模式: 低位放低位地址,高位放到高位地址
低地址 - -------- 高地址 (比如存放1 2 3 4)
0x1 0x2 0x3 0x4
小端模式
低位放高地址,高位放低地址
低地址 - -------- 高地址 (比如存放1 2 3 4)
0x4 0x3 0x2 0x1
3.存儲單元和存儲內容
每個存儲單元都有一個地址編號,被稱為存儲器的地址,在C語言中其實就是內存地址
每個存儲單元都存放了一個字節的內容.
如果取內容則是
[地址] = 取出來的值,所以C語言中的數組的中括號就是這樣來的.
4.解決CP的尋址能力
16位處理器,能處理最大的數據范圍是2^16次方數據,也就是64k,就算你裝上一個1MB的內存也訪問不到
解決:
1.8086CPU有20條地址線,最大的可尋址的控件是2 ^20次方,威力地址從00000h - FFFFFh
2.8086CPU講1MB的空間分為了很多邏輯段(Segment)
每個段的最大限制為64kb,為什么,因為寄存器是16位了,沒次尋址都是2 ^16次方
短地址的低四位為0000b,為什么,因為加了4根地址總線,也就是多了4個,所以都給4
這樣,一個存儲單元,除了有一個唯一的物理地址,還有很多的邏輯地址
現在為了解決這個尋址問題,所以用2個寄存器存儲,也就是上面為什么說CS和IP一起來確定一條物理內存執行
的下一條指令了.
而邏輯地址有很多,分了好幾段,也就是段地址了, 采用段基地址 : 段內偏移地址 這樣存儲
段地址: 段地址就是邏輯地址在主存的起始位置
8086規定段的地址必須是%16, 那么地址就是xxxx0H,因為是16進制,所以最后為0,換算成二進制就是后面4個二進制為0
因為%16地址,所以現在就能用16位的段寄存器來表示段地址了.
偏移地址
偏移地址說明主存單元距離段地址起始位置的偏移量
每段也是不超過64kb,也可以用寄存器存儲,所以 IP就出現了
物理地址和邏輯地址的轉換
講邏輯地址(段地址)左移4位(也就是 *2^4次方)加上偏移的地址,就得到了20位的物理地址
一個物理地址可以有多個邏輯地址
比如
邏輯地址 1460 : 100 物理地址就是14600 (因為*16) + 上偏移100 = 14700H
1380: F00 = 13800 + F00 = 14700H

8086中常用的段寄存器
CS(代碼段) 指定代碼段的起始地址
SS (堆棧段) 指明了對斬斷的起始地址
DS (數據段) 指明了數據段的起始地址
ES(附加段) 指明了附加端的起始地址
而這些在C語言中稱為內存4區
為什么分段:
我們上一講寫的顯示Helloworld並且寫到文件中,現在匯編的代碼和數據是在一起的,但是一旦程序更大了,就不好弄了.
作業: 使用debug編譯器,利用指令,查看標志位的狀態顯示分別是什么
第二講作業以及工具獲取連接
鏈接:http://pan.baidu.com/s/1mi3KW1U 密碼:0u0e
