第一周

第二周
:tabe fn 在一個新的标簽頁中編輯檔案fn gt 切換到下一個标簽頁 gT 切換到上一個标簽頁 :tabr 切換到第一個标簽頁 :tabl 切換到最後一個标簽頁 :tabm [N] 把目前tab移動到第N個tab之後 對,正如你所想象的那樣,跟eclipse, ue等的标簽頁是一個意思! 視窗指令 ctrl+w s 水準分割視窗 ctrl+w w 切換視窗 ctrl+w q 退出目前視窗(由于同時有多個檔案,此指令不會影響其他視窗) ctrl+w v 垂直分割視窗
:w 将緩沖區寫入檔案,即儲存修改 :wq 儲存修改并退出 :x 儲存修改并退出 :q 退出,如果對緩沖區進行過修改,則會提示 :q! 強制退出,放棄修改 查找替換 /pattern 向後搜尋字元串pattern ?pattern 向前搜尋字元串pattern n 下一個比對(如果是/搜尋,則是向下的下一個,?搜尋則是向上的下一個) N 上一個比對(同上) :%s/old/new/g 搜尋整個檔案,将所有的old替換為new :%s/old/new/gc 搜尋整個檔案,将所有的old替換為new,每次都要你确認是否替換 複制粘貼 dd 删除光标所在行 dw 删除一個字(word) x 删除目前字元 X 删除前一個字元 D 删除到行末 yy 複制一行,此指令前可跟數字,辨別複制多行,如6yy,表示從目前行開始複制6行 yw 複制一個字 y$ 複制到行末 p 粘貼粘貼闆的内容到目前行的下面 P 粘貼粘貼闆的内容到目前行的上面 ]p 有縮進的粘貼,vim會自動調節代碼的縮進 "a 将内容放入/存入a寄存器,可以支援多粘貼闆
h,j,k,l 上,下,左,右 ctrl-f 上翻一頁 ctrl-b 下翻一頁 % 跳到與目前括号比對的括号處,如目前在{,則跳轉到與之比對的}處 w 跳到下一個字首,按标點或單詞分割 W 跳到下一個字首,長跳,如end-of-line被認為是一個字 e 跳到下一個字尾 E 跳到下一個字尾,長跳 b 跳到上一個字 B 跳到上一個字,長跳 0 跳至行首,不管有無縮進,就是跳到第0個字元 ^ 跳至行首的第一個字元 $ 跳至行尾 gg 跳至檔案的第一行 gd 跳至目前光标所在的變量的聲明處 [N]G 跳到第N行,如0G,就等價于gg,100G就是第100行 fx 在目前行中找x字元,找到了就跳轉至 ; 重複上一個f指令,而不用重複的輸入fx tx 與fx類似,但是隻是跳轉到x的前一個字元處 Fx 跟fx的方向相反 ),( 跳轉到上/下一個語句 * 查找光标所在處的單詞,向下查找 # 查找光标所在處的單詞,向上查找 `. 跳轉至上次編輯位置 在螢幕上移動
H 移動光标到目前螢幕上最上邊的一行 M 移動光标到目前螢幕上中間的一行 L 移動光标到目前螢幕上最下邊的一行 書簽 ma 把目前位置存成标簽a `a 跳轉到标簽a處 編輯 r 替換一個字元 J 将下一行和目前行連接配接為一行 cc 删除目前行并進入編輯模式 cw 删除目前字,并進入編輯模式 c$ 擦除從目前位置至行末的内容,并進入編輯模式 s 删除目前字元并進入編輯模式 S 删除光标所在行并進入編輯模式 xp 交換目前字元和下一個字元 u 撤銷 ctrl+r 重做 . 重複上一個編輯指令 ~ 切換大小寫,目前字元 g~iw 切換目前字的大小寫 gUiw 将目前字變成大寫 guiw 将目前字變成小寫 >> 将目前行右移一個機關 << 将目前行左移一個機關(一個tab符) == 自動縮進目前行
插入模式 i 從目前光标處進入插入模式 I 進入插入模式,并置光标于行首 a 追加模式,置光标于目前光标之後 A 追加模式,置光标于行末 o 在目前行之下新加一行,并進入插入模式 O 在目前行之上新加一行,并進入插入模式 Esc 退出插入模式 可視模式 标記文本 v 進入可視模式,單字元模式 V 進入可視模式,行模式 ctrl+v 進入可視模式,列模式,類似于UE的列模式 o 跳轉光标到選中塊的另一個端點 U 将選中塊中的内容轉成大寫 O 跳轉光标到塊的另一個端點 aw 選中一個字 ab 選中括号中的所有内容,包括括号本身 aB 選中{}括号中的所有内容 ib 選中括号中的内容,不含括号 iB 選中{}中的内容,不含{}
對标記進行動作 > 塊右移 < 塊左移 y 複制塊 d 删除塊 ~ 切換塊中内容的大小
2. gcc
GNU CC(簡稱為gcc)是GNU項目中符合ANSI C标準的編譯系統,能夠編譯用C、C++和Object C等語言編寫的程式。gcc又是一個交叉平台編譯器,它能夠在目前CPU平台上為多種不同體系結構的硬體平台開發軟體,是以尤其适合在嵌入式領域的開發編譯。
GCC編譯代碼的過程如下:
我們可以把編譯過程分成四步,以編譯hello.c生成可執行檔案hello為例,如下圖:
- 預處理:gcc –E hello.c –o hello.i;gcc –E調用cpp
- 編 譯:gcc –S hello.i –o hello.s;gcc –S調用ccl
- 彙 編:gcc –c hello.s –o hello.o;gcc -c 調用as
- 鍊 接:gcc hello.o –o hello ;gcc -o 調用ld
編譯過程比較難記,我們簡化一下,前三步,GCC的參數連起來是“ESc”,相應輸入的檔案的字尾是“iso”,這樣記憶起來就容易多了。
學習GCC的另外一個重點是:參考教材《深入了解計算機系統》 7.6,7.10節,學習靜态庫,動态庫的制作。
info b 檢視所設斷點
break 行号或函數名 <條件表達式> 設定斷點
tbreak 行号或函數名 <條件表達式> 設定臨時斷點,到達後被自動删除
delete [斷點号] 删除指定斷點,其斷點号為”info b”中的第一欄。若預設斷點号則删除所有斷點
disable [斷點号]] 停止指定斷點,使用”info b”仍能檢視此斷點。同delete一樣,省斷點号則停止所有斷點
enable [斷點号] 激活指定斷點,即激活被disable停止的斷點
condition [斷點号] <條件表達式> 修改對應斷點的條件
ignore [斷點号]<num> 在程式執行中,忽略對應斷點num次
step 單步恢複程式運作,且進入函數調用
next 單步恢複程式運作,但不進入函數調用
finish 運作程式,直到目前函數完成傳回
c 繼續執行函數,直到函數結束或遇到新的斷點
由于設定斷點在Gdb的調試中非常重要,是以在此再着重講解一下Gdb中設定斷點的方法。
Gdb中設定斷點有多種方式:其一是按行設定斷點,設定方法在3.5.1節已經指出,在此就不重複了。另外還可以設定函數斷點和條件斷點,在此結合上一小節的代碼,具體介紹後兩種設定斷點的方法。
① 函數斷點
(gdb) b 函數名
② 條件斷點
格式為:b 行數或函數名 if 表達式
(gdb) b 8 if i==10
3. gdb
2.1預處理
可以輸出test.i檔案中存放着test.c經預處理之後的代碼。打開test.i檔案,看一看,就明白了。後面那條指令,是直接在指令行視窗中輸出預處理後的代碼.
gcc的-E選項,可以讓編譯器在預處理後停止,并輸出預處理結果。在本例中,預處理結果就是将stdio.h 檔案中的内容插入到test.c中了。
2.2編譯為彙編代碼(Compilation)
預處理之後,可直接對生成的test.i檔案編譯,生成彙編代碼:
gcc的-S選項,表示在程式編譯期間,在生成彙編代碼後,停止,-o輸出彙編代碼檔案。
2.3彙編(Assembly)
對于上一小節中生成的彙編代碼檔案test.s,gas彙編器負責将其編譯為目标檔案,如下:
2.4連接配接(Linking)
gcc連接配接器是gas提供的,負責将程式的目标檔案與所需的所有附加的目标檔案連接配接起來,最終生成可執行檔案。附加的目标檔案包括靜态連接配接庫和動态連接配接庫。
對于上一小節中生成的test.o,将其與C标準輸入輸出庫進行連接配接,最終生成程式test
在指令行視窗中,執行./test, 讓它說HelloWorld吧!
建議使用CGDB,比GDB好用,熟悉VC的調試方式,可以使用DDD。 注意使用GCC編譯時要加“-g”參數。 參考gdb參考卡GDB最基本的指令有:
- gdb programm(啟動GDB)
- b 設斷點(要會設4種斷點:行斷點、函數斷點、條件斷點、臨時斷點)
- run 開始運作程式
- bt 列印函數調用堆棧
- p 檢視變量值
- c 從目前斷點繼續運作到下一個斷點
- n 單步運作
- s 單步運作
- quit 退出GDB
4.其他
display 跟蹤變量值的改變
until 跳出循環
finish 跳出函數
help 幫助
第三周
一、數字表示
1、 無符号數:編碼基于傳統的二進制表示法表示大于或等于零的數字。
2、 補碼:編碼是表示有符号整數的最常見方法,可以是正或者是負的數字。
3、 浮點數:編碼是表示實數的科學計數法的以二位基數的版本。
- 三種數字:無符号數、有符号數(2進制補碼)、浮點數
- 溢出:計算機的表示法是用有限數量的位來對一個數字編碼,當結果太大以至不能表示時,會溢出
- 整數運算:編碼的數值範圍較小,精确;浮點運算:數值範圍較大,近似,不可結合
§1 資訊存儲
- 最小的可尋址的存儲器機關:位元組(8位)
- 虛拟存儲器、位址、虛拟位址空間(p22)
進制轉換
十六進制表示法
十六進制中一個位元組的值域為00H~FFH
用0x或0X開頭表示十六進制數字常量
快捷算法:要表示的數字常量為x=2^n,n=i+4j,且0≤i≤3時,開頭的十六進制數字為1(i=0)、2(i=1)、4(i=2)、8(i=3),後面跟随着j個十六進制的0。這裡的j是代表着每四位二進制位對應的十六進制位,而i的範圍是因為十六進制中每一位的範圍是0-F
二、字
字長:指明整數和指針資料的标稱大小。決定虛拟位址空間的最大大小
字長為w,虛拟位址範圍為0~2^w-1,程式最多通路2^w個位元組,cpu一次處理w位資料
三、資料大小
在不同字長的計算機中,相同的資料類型所占用的位元組數不同
在64位機上生成32位代碼:gcc -m32
32位與64位機器中的資料大小
C聲明 | 32位機器 | 64位機器 |
char | 1 | |
short int | 2 | |
int | 4 | |
long int | 8 | |
long long int | ||
char * | ||
float | ||
double |
四、尋址和位元組順序
多位元組對象倍存儲為連續的位元組序列,對象的位址為所使用位元組中最小的位址
位元組順序是網絡程式設計的基礎
1.兩個通用規則(w為整數,位表示為[Xw-1,Xw-2,……,X1,X0],其中Xw-1是最高有效位,X0是最低有效位):
- 小端法:最低有效位元組在最前面(大多數Intel相容機)
- 大端法:最高有效位元組在最前面(大多數IBM和Sun Microsystems機器)
- 一些新的微處理器使用雙端法
位元組内部的順序不變
反彙編器:确定可執行程式檔案所表示的指令序列的工具;将可執行程式檔案轉換回可讀性更好的ASCII碼形式的程度
2.強制類型轉換
表示字元串
c語言中字元串被編碼成為一個以null(值為0)字元結尾的字元數組
指令man ascii:得到ASCII字元碼表
表示代碼
二進制代碼在不同的作業系統上有不同的編碼規則。是以二進制代碼是不相容的
布爾代數
1.最簡單布爾代數:與& 或| 非~ 異或^(結果為0或1)
2.擴充的布爾運算:位向量的運算(結果仍是位向量)
位向量的應用:表示有限集合,對集合編碼
位級運算
1.将位向量按位進行邏輯運算,結果仍是位向量
2.掩碼運算
掩碼:用來選擇性的屏蔽信号,是一個位模式,表示從一個字中選出的位的集合。
用位向量給集合編碼,通過指定掩碼來有選擇的屏蔽或者不屏蔽一些信号,某一位位置上為1時,表明信号i是有效的;0表示該信号被屏蔽。這個掩碼就表示有效信号的集合。
0xFF:屏蔽除最低有效位元組之外的所有位元組。
~0:生成全1的掩碼
邏輯運算
1.邏輯運算符:與&& 或|| 非!
2.計算方法:所有非零參數都代表TRUE,0參數代表FALSE。1代表TRUE,0代表FALSE
- 隻有當參數被限制為0或1時,邏輯運算才與按位運算有相同的行為。
- 如果對第一個參數求值就能确定表達式的結果,邏輯運算符就不會對後面的參數求值。
移位運算
C語言還提供了一組移位運算,以便向左或向右移動位模式。移位運算可以從左向右結合的,是以x<<j<<k等價于(x<<j)<<k。
一般而言,機器支援兩種形式的右移:邏輯右移和算數右移。邏輯右移在最左端補k個0,算數右移在最左端補k各最高有效位的值。
C語言标準沒有明确定義應該使用哪種類型的右移。對于無符号資料,右移必須是邏輯的。對于有符号資料,算數的或者邏輯的右移都可以。
C語言中有符号數和無符号數的轉換
位向量不變,隻是上下文的讀取方式不同,是以根據不同的讀取規則,最終的讀取結果也不同。這就是所謂的資訊就是位+上下文。
注:c語言中要建立一個無符号常量,必須加上字尾字元'U'或者'u'。
轉換的原則是底層的位表示保持不變。
怎麼讓負數等于正數
将有符号負數轉化為無符号正數,變的隻是上下文的讀取方式,但二進制位級表示是一樣的。
零擴充和符号擴充
零擴充:将一個無符号數轉換為一個更大的資料類型,我們隻需要簡單地在開頭添加0。
号擴充:将一個補碼數字轉換為一個更大的資料類型,規則是在表示中添加最高有效位的值的副本。
無符号數與有符号數容易造成的錯誤
例:以下一段代碼
float sum_elements(float a[],unsigned length){
int i;
float result=0;
for(i=0;i<=length-1;i++)
result+=a[i];
return result;
}
因為參數length是無符号的,計算0-1将進行無符号運算,這等價于模數加法。結果得到UMax。<=比較進行同樣使用無符号數比較,而因為任何數都是小于或者等于UMax的,是以這個比較總是為真!是以,代碼将試圖通路數組a的非法元素。
改正方法:1.将length聲明為int類型。
2.或将for循環的測試條件改為i<length。
整數溢出
整數溢出:指完整的整數結果不能放到資料類型限制的字長中去。
避免整數溢出:當兩個整數進行運算時,其結果用更大的資料類型進行存儲。比如兩個int類型的整數相乘的結果用long long資料類型的變量來存儲。
關于整數運算的思考
計算機執行的"整數"運算實際上是一種模運算形式。表示數字的有限字長限制了可能的值的取值範圍,結果運算可能溢出。
補碼提供了一種既能表示負數也能表示正數的靈活方法,同時使用了與執行無符号算數相同的位級實作,這些運算包括加減乘除,無論是以無符号形式還是以補碼形式表示的,都有完全一樣或者非常類似的位級行為。
浮點數
浮點表示對形如V=x*的有理數進行編碼。它對涉及非常大的數字(| V|>>0)、非常接近于0(|V|<<1)的數字,以及更普遍地作為實數運算的近似值的計算,是很有用的。
浮點數的運算及執行标準:IEEE标準754。
浮點數運算的不精确性和舍入
當一個數字不能精确地表示為IEEE标準754時,就必須向上或者向下調整,此時出現舍入。
IEEE浮點标準,float和double類型p70
單精度浮點格式(float)中,s、exp和frac字段分别為1位、k=8位和n=23位,得到一個32位的表示。
雙精度浮點格式(double)中,s、exp和frac字段分别為1位、k=11位和n=52位,得到一個64位的表示。
整數與浮點數轉換規則
當在int、float和double格式之間進行強制類型轉換時,程式改變數值和位模式的原則如下(假設int是32位的):
- 從int轉換成float,數字不會溢出,但是可能被舍入。
- 從int或float轉換成double,因為double有更大的範圍(也就是可表示值的範圍),也有更高的精度(也就是有效位數),是以能夠保留精确的數值。
- 從double轉換成float,因為範圍要小一些,是以值可能溢出為+∞或-∞。另外由于精确度較小,它還可能被舍入。
- 從float或者double轉換為int,值将會向零舍入。
第四周
1.P104\P105
X86 尋址方式經曆三代:
-DOS時代的平坦模式,不區分使用者空間和核心空間,很不安全
-8086的分段模式
-IA32的帶保護模式的平坦模式
2.P106
ISA:機器級程式的格式和行為,定義為指令集體系機構,它定義了處理器狀态指令的格式,以及每條指令對狀态的影響。
機器級程式使用的存儲器位址是虛拟位址,提供的存儲器模型看上去是一個非常大的字元數組
PC:程式計數器。在IA32中,用%eip表示,訓示将要執行的下一條指令在存儲器中的位址。
程式存儲器:包含程式的可執行機器代碼,作業系統需要的一些資訊,用來管理過程調用和傳回的運作時棧,以及使用者配置設定的存儲器塊。
3.P107
64位機上想得到32位代碼:gcc -m32 -S xxx.c
編譯并産生彙編目标檔案xxx.o:gcc -O1 -c xxx.c
獲得彙編代碼:gcc -S xxx.c -o xxx.s
Ubuntu中獲得彙編代碼:gcc -S xxx.c更接近教材
教材中獲得彙編代碼:gcc -O1 -S xxx.c(編譯器使用的事第一級優化)
4.P108
二進制檔案可用od指令檢視,也可以用gdb的x檢視:(gdb)x/17xb sum表示檢查17個十六進制的位元組;
顯示代碼過多或過少可用more、less結合管道檢視,也可以用輸出重定向:
od xxx.o | more
od xxx.o > xxx.txt
5.P109
gcc -S 産生的彙編中可以把 以”.“開始的語句都删除了再閱讀
6.P110
Linux和windows的彙編格式的差別:
-Intel代碼省略了訓示大小的字尾,即'l'
-Intel代碼省略了寄存器名字前面的‘%’符号,用的是esp,而不是%esp
-Intel代碼用不同的方式來描述存儲器中位置
-在帶有多個操作數的指令情況下,列出操作數的順序相反
7.P111
-db char 1
-dw short int 2
-dd int 或float 4
-dq long int 或 double 8
8.P112
-esi、edi可以用來操縱數組,esp、ebp用來操縱棧幀。
-通用寄存器中的eax,ebx,ecx,edx中,32位的eax,16位的ax,8位的ah,al都是獨立的。例如:假定目前是32位x86機器,eax寄存器的值為0x8226,執行完addw $0x8266, %ax指令後eax的值是多少?
解析:0x8226+0x826=0x1044c, ax是16位寄存器,出現溢出,最高位的1會丢掉,剩下0x44c,不要以為eax是32位的不會發生溢出。
多數情況下,前6個寄存器為通用寄存器,最後兩個寄存器儲存着指向程式棧中重要位置的指針。
另外,位元組操作指令可以獨立的讀或者寫前4個寄存器的2個低位位元組。
9.P113
操作數的三種類型:立即數(常數值)、寄存器(某個寄存器的内容)、存儲器(根據計算出來的位址通路某個存儲器位置)
-有效位址的計算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
10.P114
-MOV:相當于C語言的指派“=”,将源操作數的值複制到目的操作數中;
MOVS:将一個較小的源資料複制到一個較大的資料位置,高位用位擴充;
MOVZ:将一個較小的源資料複制到一個較大的資料位置,高位用零擴充。
-push:把資料壓入棧中;
pop:删除資料。
11.P115\P116
-棧頂元素的位址是所有棧中元素位址中最低的
-棧指針%esp儲存棧頂元素的位址。
12.P117
-指針就是位址
-局部變量儲存在寄存器中
13.P119
按目的操作數分類:
第一類:加載有效位址。實際是将有效位址寫入目的操作數,目的操作數必須是寄存器。
第二類:一進制操作。操作數既是源又是目的。可以是寄存器也可以是存儲器。
第三類:二進制操作。第二個操作數既是源又是目的。但兩個操作數不能同時是存儲器。
第四類:移位操作。位移量是一個立即數或放在單位元組寄存器%cl中。移位操作的目的操作數可以是一個寄存器或是一個存儲器位置。
14.P123\P124
有條件跳轉(實作if,switch,while,for)
無條件跳轉jmp(實作goto)
15.P125
SET指令根據t=a-b的結果設定條件碼
16.P127
跳轉指令(導緻執行切換到程式中一個全新的位置,跳轉的目的地通常用一個标号指明)
無條件跳轉:JMP 可以是直接跳轉也可以是間接跳轉(寫法是*後面加操作數訓示符)
有條件跳轉:根據條件碼的某個組合,或者跳轉或者繼續執行下一條指令
17.P130-P145
-條件分支——if-else結構:在兩個分支語句中選擇執行一個,彙編實作通過goto,就是彙編器為兩個分支産生各自的代碼塊,它會插入條件和無條件分支,以保證能執行正确的代碼塊。
-循環結構——do-while、while、for:用條件測試和跳轉組合實作循環的效果。大多數彙編器根據do-while形式來産生循環代碼,其他的循環會首先轉換成do-while形式,然後再編譯成機器代碼。
-switch語句:根據一個整數索引值進行多重分支。通過使用跳轉表這種資料結構實作更加高效。跳轉表是一個數組,表項i是一個代碼段的位址,這個代碼段實作當開關索引值為i時程式該做的。此時跳轉可以用goto/jmp
18.P149
IA32通過程式棧來實作過程調用
19.P150\P151
call指令\ret指令
函數傳回值存在%eax中
20.P174
關于棧幀的gdb指令bt/frame/up/down
指令 | 描述 |
---|---|
backtrace(或bt) | 檢視各級函數調用及參數 |
finish | 連續運作到目前函數傳回為止,然後停下來等待指令 |
frame(或f) 幀編号 | 選擇棧幀 |
info(或i) locals | 檢視目前棧幀局部變量的值 |
list(或l) | 列出源代碼,接着上次的位置往下列,每次列10行 |
list 行号 | 列出從第幾行開始的源代碼 |
list 函數名 | 列出某個函數的源代碼 |
next(或n) | 執行下一行語句 |
print(或p) | 列印表達式的值,通過表達式可以修改變量的值或者調用函數 |
quit(或q) | 退出 gdb |
set var | 修改變量的值 |
start | 開始執行程式,停在 main |
step(或s) | 執行下一行語句,如果有函數調用則進入到函數中 |
break(或b) 行号 | 在某一行設定斷點 |
break 函數名 | 在某個函數開頭設定斷點 |
break ... if ... | 設定條件斷點 |
continue(或c) | 從目前位置開始連續運作程式 |
delete breakpoints | 删除斷點 |
display 變量名 | 跟蹤檢視某個變量,每次停下來都顯示它的值 |
disable breakpoints | 禁用斷點 |
enable 斷點号 | 啟用斷點 |
info(或i)breakpoints | 檢視目前設定了哪些斷點 |
run(或r) | 從頭開始連續運作程式 |
undisplay 跟蹤顯示号 | 取消跟蹤顯示 |
watch | 設定觀察點 |
info(或i) watchpoints | 檢視目前設定了哪些觀察點 |
x | 從某個位置開始列印存儲單元的内容,全部當成位元組來看,而不區分哪個位元組屬于哪個變量 |
第五周
4.1 Y86指令集體系結構
一、程式員可見的狀态
程式員可見狀态:程式中的每條指令都會讀取或修改處理器狀态的某些部分
--8個程式寄存器:%eax,%ecx,%edx,%ebx,%esi,%edi,%esp,%ebp.他們都可以存儲一個字;
%esp被入棧、出棧、調用和傳回指令作為棧指針;
其他情況時寄存器沒有固定的含義或固定值
--3個一位條件碼:ZF、OF、SF.儲存最近的算術或邏輯指令所造成影響的有關資訊
--PC(程式計數器):存放目前正在執行指令的位址。
--存儲器:一個很大的位元組數組,儲存着程式和資料;
Y86用虛拟位址來引用存儲器位置,硬體和作業系統軟體聯合起來将虛拟位址翻譯成實際或實體位址,指明資料實際儲存在存儲器中哪個地方
--Stat:狀态碼,程式狀态的最後一個部分,表明程式執行的總體狀态,訓示是正常運作還是出現了某種異常
二、Y86指令
--halt:這個指令将會終止指令的執行。
--nop:這是一個占位指令,它不做任何事情,後續為了實作流水線,它有一定的作用。
--xxmovl:這是一系列的資料傳送指令,其中r代表寄存器,m代表存儲器,i代表立即數。比如rrmovl指令,則代表将一個寄存器的值,賦給另外一個寄存器。
--opl:操作指令,比如加法,減法等等。
--jxx:條件跳轉指令,根據後面的條件進行跳轉。
--cmovxx:條件傳送指令,後面的xx代表的是條件。特别的是,條件傳送隻發生在兩個寄存器之間,不會将資料傳送到存儲器。
--call與ret:方法的調用和傳回指令。一個将傳回位址入棧,并跳到目标位址。一個将傳回位址入PC,并跳到傳回位址。
--push與pop:入棧和出棧操作。
三、指令編碼
--對于opl、jxx、cmovxx指令來說,都有一個fn辨別,占用4個二進制位(半個位元組)。這個便是指令的功能部分,這個是由于它們的指令編碼一樣,但功能有所不同所造成的。比如對于opl,就有加、減、與、異或等操作,那麼它們的指令編碼第一個位元組就分别為十六進制的60、61、62、63。
--Y86指令集圖中可看見指令的位元組級編碼。每條指令需要1-6個位元組不等。每條指令的第一個位元組表明指令的類型。這個位元組分為兩個部分,每部分4位:高4位是代碼部分,低4位是功能部分。功能值隻有在一組相關指令共用一個代碼時才有用。
--有的指令隻有一個位元組長,因為可能附加有寄存器訓示符位元組,指定一個或兩個寄存器。這些寄存器字段為rA,rB。有則有,無則無,隻有一個的則将第二個設為0xF。
四、Y86異常
--對于Y86來說,程式猿可見的狀态中就有stat狀态碼,它辨別了程式執行的狀态。Y86需要有能力根據stat去做一些處理。不過為了簡單起見,這裡除了正常執行之外,都将停止指令的執行。真實當中,會有專門的異常處理程式。
--Y86有四種不同的狀态碼,AOK(正常)、HLT(執行halt指令)、ADR(非法位址)和INS(非法指令)。
五、Y86程式和Y86指令詳情
--比如對于X86指令中的 addl $4,%ecx 這樣的指令,由于Y86當中的addl指令中不包含立即數,是以Y86需要先将立即數存入寄存器,即使用irmovl指令,然後再使用addl來處理加法運算。
--建立Y86代碼的唯一工具是彙編器。
--以“.”開頭的詞是彙編指令,他們告訴彙編器調整位址,以便在那兒産生代碼或插入一些資料。指令.pos0告訴編譯器應該從位址0處開始産生代碼。這個位址是所有Y86程式的起點。
4.2 邏輯設計和硬體控制語言HCL
一、邏輯門
--邏輯門産生的輸出,等于它們輸入位值的某個布爾函數。
--
AND &&
OR ||
NOT !
二、組合電路和布爾表達式
--兩個或多個邏輯門的輸出不能連接配接在一起,否則可能會使線上的信号沖突,導緻一個不合法的電壓或電路故障。
--網必須無環。
三、字級的組合電路和HCL整數表達式
--所有字級的信号都聲明為int,不指定字的大小
--算數/邏輯單元(ALU)是很重要的組合電路,有三個輸入,标号為A、B的兩個資料輸入和一個控制輸入。根據控制輸入的設定,電路會對資料輸入執行不同的算數或邏輯操作。
四、集合關系
--判斷集合關系的通用格式是:
iexpr in {iexpr1,iexpr2,...,iexprk}
五、存儲器和時鐘
--時鐘寄存器(簡稱寄存器)存儲單個位或字,時鐘信号控制寄存器加載輸入值
--随機通路存儲器(簡稱存儲器)存儲多個字,用位址來選擇該讀或該寫哪個字
4.3 Y86的順序實作
一、将處理組織成階段
--取指:取指階段從存儲器讀取指令位元組,位址為程式計數器PC的值
--譯碼:譯碼階段從寄存器檔案讀入最多兩個操作數
--執行:在執行階段,算數/邏輯單元要麼根據ifun的值執行指令指明的操作,計算機存儲器引用的有效位址,要麼增加或減少棧指針
--訪存:訪存階段可以将資料寫入存儲器,或從存儲器讀出資料
--寫回:寫回階段最多可以寫兩個結果到寄存器檔案
--更新PC:将PC設定成下一條指令的位址
二、SEQ硬體結構和時序:看書上P258圖
三、SEQ階段的實作
--取指階段:取指階段包括指令存儲器硬體單元。以PC作為第一個位元組(位元組0)的位址,這個單元一次從存儲器讀出6個位元組,第一個位元組被解釋稱指令位元組,分為兩個4位數。标号為“icode”和“ifun”的控制邏輯塊計算指令和功能碼等于從存儲器讀出值,或者當指令位址不合法時(imem_error指明),這些值對應于nop指令。
--譯碼和寫回階段:都要通路寄存器檔案。寄存器檔案有四個端口,支援同時進行兩個讀(端口A、B)和兩個寫(E、M),每個端口都有一個位址連接配接和一個資料連接配接。根據指令代碼icode以及寄存器訓示值rA和rB,可能還會根據執行階段計算出的Cnd條件信号。
--執行階段:執行階段包括算術/邏輯單元(ALU)第一步每條指令的ALU計算,執行階段還包括條件碼寄存器。
--訪存階段:訪存階段的任務是讀或者寫程式資料,兩個控制塊産生存儲器位址和存儲器輸入資料的值,另外兩個塊産生控制信号表明應該執行讀操作還是寫操作。當執行讀操作時資料存儲器産生值valM。
--更新PC階段:SEQ中最後一個階段會産生程式計數器的新值,依據指令的類型和是否要選擇分支,新的PC可能是valC、valM、valP
第六周
三種常見存儲技術:RAM/ROM/磁盤
(1)随機通路存儲器RAM
- 兩類:靜态RAM(SRAM)和動态RAM(DRAM)
- 靜态RAM(SRAM)比動态RAM(DRAM)更快,但也貴很多。
- 靜态RAM
- SRAM将每個位存儲在一個雙穩态的存儲器單元裡,每個單元是用一個六半導體電路來實作的。
- 這個電路的一個屬性:它可以無限制地保持在兩個不同的電壓配置或狀态之一。其他任何狀态都是不穩定的。
- 特點:由于SRAM的雙穩态特性,隻要有電,它就會永遠地保持它的值,即使有幹擾,如電子噪音,來擾亂電壓,當幹擾消除,電路也能恢複到穩定值。 - 應用:SRAM用來作為高速緩存存儲器,即可以在CPU晶片上,也可以在片下。
- 動态DRAM
- DRAM将每個位存儲為對電容的充電。電容約為30×10-15F。
- 特點:對幹擾特别敏感,當電容的電壓被擾亂之後,它就永遠不會恢複了。暴露在光線下會導緻電容電壓改變。
- - FLASH:閃存,基于EEPROM。(固态硬碟SSD基于閃存)
- 存儲在ROM裝置中的程式通常稱為固件。
(3)通路主存
- 讀事務:從主存傳送資料到CPU。 - 寫事務:從CPU傳送資料到主存。 - 總線:一組并行的導線,能攜帶位址、資料的控制信号。 資料總線、控制總線、位址總線
- 讀事務語句
movl A,%eax
- CPU從總線讀出字x,并将它copy到寄存器eax中。
-
寫事務語句
-
movl %eax,A
(4)磁盤存儲
- 磁盤構造
- 由盤片構成,每個盤片有兩面或者稱為表面,表面覆寫着磁性記錄材料。盤片中央有一個可以旋轉的主軸,使得盤片以固定的旋轉速率旋轉,通常是5400~15000轉每分鐘(RPM)
- 每個表面是由一組稱為磁道的同心圓組成;每個磁道被劃分成一組扇區;每個扇區包含相等數量的資料位(通常是512位元組);這些資料編碼在扇區上的磁性材料中。扇區之間由一些間隙分隔開,這些間隙中不存在資料位。間隙存儲用來辨別扇區的格式化位。
- 磁盤容量
- 一個磁盤上可以記錄的最大位數稱為它的最大容量/容量。
- 磁盤容量的決定因素:
- 記錄密度:磁道一英寸的段可以放入的位數。 - 磁道密度:從盤片中心出發半徑上一英寸的段内可以有的磁道數。 - 面密度:記錄密度與磁道密度的乘積。
- DRAM将每個位存儲為對電容的充電。電容約為30×10-15F。
學習總結
老師提高我的學習能力,傳授了科學的學習方法,以改變我不良的學習思維習慣為出發點,我在上課後及時消化課上知識,學習到不要就題論題,要靈活運用老師所講知識舉一反三,觸類旁通,尤其是對我這種學習成績并不是特别優秀的學生,學習後應遵循“複習為主,少做精練”的原則。古語說得好,溫故而知新,我絕不能忽視舊課複習,一味地關注下半學期新課的學習,應充分利用下課将上半學期舊課知識的疑點、難點、重點進行有效地查漏補缺。