20135203齊嶽 信息安全系統設計基礎第四周學習總結程序員
學習計時:共17小時數組
理解函數調用棧幀的概念,並能用GDB進行調試安全
深化、實踐題目,額外加分less
Linux使用平坦尋址方式,使程序員將整個存儲空間看作一個大的字節數組。函數
指令集體系結構,機器級程序的格式和行爲,它定義了處理器狀態、指令的格式以及每條指令對狀態的影響。oop
程序計數器(一般稱爲PC,用%eip表示),指示將要執行的下一條指令在存儲器中的地址。學習
整數寄存器文件:存儲地(對應於C語言的指針)或整數數據。編碼
條件碼寄存器:保存着最近執行的算數或邏輯指令的狀態信息,用來實現控制或者數據流中的條件變化。翻譯
浮點寄存器:用來存放浮點數據。設計
C預處理器插入宏和頭文件:gcc -E xxx.c -o xxx.i
編譯器產生源代碼的彙編代碼:gcc -S xxx.i -o xxx.s
彙編器化成二進制目標代碼:gcc -c xxx.s -o xxx.o
連接器生成最終可執行文件:gcc xxx. -o xxx
用objdump -d xxx.o -o xxx.s 反彙編
創建函數調用棧幀的彙編代碼:
pushl %ebp 將寄存器%ebp中的內容壓入程序棧 movl %esp,%ebp 將%ebp中的內容放入寄存器%esp ...... popl %ebp 寄存器%ebp中內容出棧 ret 返回結果
注意:
64位機器上想要獲得32代碼:gcc -m32 -S xxx.c
MAC OS中沒有objdump, 有個基本等價的命令otool
Ubuntu中 gcc -S code.c (不帶-O1) 產生的代碼更接近教材中代碼(刪除"."開頭的語句)
找到程序的字節表示:
(gdb) x/17xb sum
二進制文件能夠用od命令查看,也能夠用gdb的x命令查看。有些輸出內容過多,咱們可使用 more或less命令結合管道查看,也可使用輸出重定向來查看
od code.o | more od code.o > code.txt
·開頭的行都是指導彙編器和連接器的命令,gcc -S 產生的彙編中能夠把 以‘.’開始的語句都刪除了再閱讀
Linux和Windows的彙編格式的區別:
大多數GCC生成的彙編代碼指令都有一個字符後綴,代表操做數的大小。
(P111表格)
一個IA32中央處理單元(CPU)包含一組8個存儲32位值的寄存器。用來存儲整數數據和指針。
%eax %ax (%ah %al) 通用寄存器 %ecx %cx (%ch %cl) 通用寄存器 %edx %dx (%dh %dl) 通用寄存器 %ebx %bx (%bh %bl) 通用寄存器 %esi %si 用來操縱數組 %edi %di 用來操縱數組 %esp %sp 操縱棧幀 %ebp %bp 操縱棧幀
注意:
對於32位的eax,16位的ax,8位的ah,al都是獨立的,咱們經過下面例子說明:
假定當前是32位x86機器,eax寄存器的值爲0x8226,執行完addw $0x8266 ,%ax指令後eax的值是多少? 解析:0x8226+0x826=0x1044c, ax是16位寄存器,出現溢出,最高位的1會 丟掉,剩下0x44c,不要覺得eax是32位的不會發生溢出.
根據操做數的不一樣類型,尋址方式可分爲如下三種:
當即數尋址方式:操做數爲常數值,寫做$後加一個整數。
寄存器尋址方式:操做數爲某個寄存器中的內容
存儲器尋址方式:根據計算出來的地址訪問某個存儲器的位置
尋址模式:一個當即數偏移Imm,一個基址寄存器Eb,一個變址寄存器Ei,一個比例因子s(必須爲1,2,4,8)有效地址計算爲:Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
MOV至關於C語言的賦值'='
mov S,D S中的字節傳送到D中
注意:
push和pop:
pushl S R[%esp] ← R[%esp]-4 M[R[%esp]] ← S popl D D ← M[R[%esp]] R[%esp] ← R[%esp]+4
注意:
leal,從存儲器讀數據到寄存器,而從存儲器引用的過程其實是將有效地址寫入到目的操做數。目的操做數必須是一個寄存器。
一元操做:只有一個操做數,既是源又是目的,能夠是一個寄存器或者存儲器。
二元操做:第二個操做數既是源又是目的,兩個操做數不能同時是存儲器。
先給出位移量,而後是位移的數值,可進行算數和邏輯右移。移位操做移位量能夠是當即數或%cl中的數。
描述最近的算數或者邏輯操做的屬性,能夠檢測這些寄存器來執行條件分支指令。
CF:進位標誌,最近操做使高位產生進位,用來檢測無符號操做數的溢出 ZF:零標誌,最近操做得出的結果爲0 SF:符號標誌,最近操做獲得的結果爲負數 OF:溢出標誌,最近操做致使一個補碼溢出-正溢出或負溢出。
注意:
SET指令根據t=a-b的結果設置條件碼
控制中最核心的是跳轉語句:
有條件跳轉(實現if,switch,while,for)
無條件跳轉jmp(實現goto)
當執行PC相關的尋址時,程序計數器的值是跳轉指令後面那條指令的地址,而不是跳轉指令自己的地址。
將條件和表達式從C語言翻譯成機器代碼,最經常使用的方式是結合有條件和無條件跳轉。
C語言中if-else語句的通用形式:
if(test-expr) then-statement else else-statement
彙編結構:
t=test-expr; if!(t) goto false; then-statement goto done; false: else-statement done:
C語言中do-while語句的通用形式:
do body-statement while(test-expr);
彙編結構:
loop: body-statement t=test-expr; if(t) goto loop;
C語言中while語句的通用形式:
while(test-expr) body-statement
彙編結構:
t=test-expr; if(!t) goto done; loop: body-statement t=test-expr; if(t) goto loop; done:
C語言中for語句的通用形式:
for(init-expr;test-expr;update-expr) body-statement
彙編結構:
init-expr t=test-expr; if(!t) goto done; loop: body-statement update-expr; t=test-expr; if(t) goto loop; done:
根據一個整數索引值進行多重分支,執行switch語句的關鍵步驟是經過跳轉表來訪問代碼位置,使結構更加高效。
數據傳遞、局部變量的分配和釋放經過操縱程序棧來實現。
爲單個過程分配的棧叫作棧幀,寄存器%ebp爲幀指針,而寄存器指針%esp爲棧指針,程序執行時棧指針移動,大多數信息的訪問都是相對於幀指針。
棧向低地址方向增加,而棧指針%esp指向棧頂元素。
call:目標是指明被調用過程起始的指令地址,效果是將返回地址入棧,並跳轉到被調用過程的起始處。
ret:從棧中彈出地址,並跳轉到這個位置。
函數返回值存在%eax中
程序寄存器是惟一能被全部過程共享的資源,調用者保存寄存器 和 被調用者保存寄存器是分開的,對於哪個寄存器保存函數調用過程當中的返回值要有統一的約定。
backtrace/bt:打印當前的函數調用棧的全部信息。後面加n或-n表示打印棧頂上n層(或者下n層)的棧信息。
frame n:n爲棧中的層編號,從0開始,相似C語言中數組的下標。移動到n指定的棧幀中去,並打印選中的棧的信息。若是沒有n,則打印當前幀的信息。
up n:表示向棧的頂移動n層。
down n:表示向棧底移動n層。
(此處爲百度+本身翻譯,若有不許請指正)
C語言代碼:
int q(int x) { return x + 2; } int y(int x) { return q(x); } int main(void) { return y(7) + 9; }
使用gcc –S –o main.s main.c -m32命令編譯成彙編代碼以下:
q: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax addl $2, %eax popl %ebp ret y: pushl %ebp movl %esp, %ebp pushl 8(%ebp) call q addl $4, %esp leave ret main: pushl %ebp movl %esp, %ebp pushl $7 call y addl $4, %esp addl $9, %eax leave
3.16
testl %eax,%eax
jle .L3
如何能判斷條件爲a<=0?(對test語句理解不到位)
3.23
leal (%eax,%eax),%edx movl %ebx,%eax
(%eax中存放着val,%ebx中存放x。)
這兩行代碼如何實現val<<1的效果。
3.30
call next next: popl %eax
call指令的效果是將 返回地址入棧,也就是call後面指令的地址,即popl %eax,而%eax的值又被設置爲popl指令的地址,整個過程是順序執行的而並無發生跳轉,因此無需ret彈出。這種理解正確嗎?
爲何它是實現將程序計數器 放到整數寄存器中的惟一方式?
對於跳轉指令和循環語句的彙編代碼閱讀仍是不熟練,感受書上的例題沒有徹底吃透,在分析棧幀結構時順序執行的代碼基本能夠搞清楚,涉及到call和ret相關的語句時就感受比較困難,還須要深刻理解。