不區分用戶空間和內核空間,很不安全html
gcc -01 -o p p1.c
-01:表示使用第一級優化。一般提升優化級別會使最終程序運行得更快,可是編譯時間可能會變長,用調試工具對代碼進行調試會更困難。(實際中,第二級優化-02被認爲是較好的選擇)程序員
gcc命令調用一系列程序將源代碼轉換成可執行代碼: - C預處理器 擴展源代碼,插入#include命令指定的文件,擴展#define聲明指定的宏。(.i) - 編譯器 產生兩個源代碼的彙編代碼。(.s) - 彙編器 將彙編代碼轉化成二進制目標代碼(.o) - 鏈接器 將兩個目標代碼與實現庫函數的代碼合併,併產生最終的可執行代碼文件。
參考資料3:體系結構-指令集結構編程
計算機系統使用了多種不一樣形式的抽象,利用更簡單的抽象模型來隱藏實現的細節。對於機器級編程來講,兩種抽象尤其重要:數組
機器級程序的格式和行爲,定義爲 ISA :指令集體系結構。安全
ISA,定義了處理器狀態,指令格式,以及每條指令對狀態的影響。 處理器的硬件併發的執行許多指令,可是能夠採起措施保證總體行爲與ISA指定的順序整形徹底一致。 解決的問題: 指令的編碼方式(即如何編碼) 操做數和操做結構的存放位置 數據的類型和大小 支持哪些操做 下一條指令的地址
機器級程序使用的存儲器地址是虛擬地址,提供的存儲器模型看上去是一個很是大的字節數組。數據結構
一些一般對C語言程序員隱藏的機器代碼在IA32中是可見的:併發
指示將要執行的下一條指令在存儲器中的地址。less
包含8個命名的位置,分別存儲32位的數值,這些寄存器能夠存儲地址(對應C語言的指針)或整數數據,有的寄存器被用來記錄某些重要的程序狀態,其餘的寄存器用來保存臨時數據,例如過程的局部變量和函數的返回值。函數
保存着最近執行的算術或邏輯指令的狀態信息,他們用來實現控制或數據流中的條件變化。工具
一組浮點寄存器存放浮點數據
一條機器指令只執行一個很是基本的操做
參考資料4:函數調用過程棧幀變化詳解
教材代碼:
得到彙編代碼:
gcc -S xxx.c -o xxx.s
反彙編:
objdump -d xxx
彙編代碼(函數前兩條和後兩條彙編代碼,全部函數都有,創建函數調用棧幀):
前兩條: pushl %ebp 將寄存器%ebp的內容壓入程序棧 movl %esp,%ebp 獲得新棧低,將當前棧頂賦予棧低 後兩條: popl %ebp 過程調用結束,恢復舊棧低 ret 子程序的返回指令
注意:
實驗樓中:
二進制文件能夠用od 命令查看,也能夠用gdb的x命令查看。
有些輸出內容過多,可使用 more或less命令結合管道查看,也可使用輸出重定向來查看。
od code.o | more od code.o > code.txt
字(word) 16位 雙字(double words) 32位 四字(quad words) 64位
一個IA32的中央處理器單元包含一組8個存儲32位數值的寄存器。全部八個寄存器均可以做爲16位(字)或32位(雙字)來訪問。
存儲器,根據計算出來的地址(有效地址)訪問某個存儲器位置。
操做數格式:
有效地址的計算方式
Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
參考資料5:彙編(五)——數據傳送指令一
參考資料6:彙編(八)——數據傳送類指令三
符號 意義 r8 任意一個8位通用寄存器AH/AL/BH/BL/CH/CL/DH/DL r16 任意一個16通用寄存器AX/BX/CX/DX/SI/DI/BP/SP reg 表明r8或r16 seg 段寄存器CS/DS/ES/SS m8 一個8位存儲器操做數單元(包括全部主存尋址方式) m16 一個16位存儲器操做數單元(包括全部主存尋址方式) mem 表明m8或m16 i8 一個8位當即數 i16 一個16位當即數 imm 表明i8或i16 dest 目的操做數 src 源操做數
mov指令(指令的第一個是源操做數,第二個是目的操做數)
MOV reg/mem,imm 當即數送寄存器或是存儲器 MOV reg/mem/seg,reg 寄存器送寄存器(包括段寄存器)或貯存 MOV reg/seg,mem 主存送寄存器(包括段寄存器) MOV reg/mem,seg 段寄存器送主存或寄存器
IA32的限制:兩個操做數都不能指向存儲器。
不能從內存地址直接MOV到另外一個內存地址,要用寄存器中轉一下。
push與pop
棧向下增加,棧頂元素的地址是全部棧中元素地址中最低的。棧指針%esp保存棧頂元素的地址。
進棧指令PUSH: PUSH reg/mem/seg SP←SP-2,SS←reg/mem/seg - 進棧指令先使堆棧指令SP減2,而後把一個字操做數存入堆棧頂部。 - 堆棧操做的對象只能是字操做數。 - 進棧時,底字節存放於低地址,高字節存放在高地址,SP相應向低地址移動兩個字節單元。 出棧指令POP: POP reg/seg/mem reg/seg/mem←SS:[SP],SP←SP+2 - 出棧指令把棧頂的一個字傳送至指定的目的操做數,而後堆棧指針SP加2。 - 目的操做數應爲字操做數。 - 字從棧頂彈出時,低地址字節送低字節,高地址字節送高字節。
是movl指令的變形
一元操做
- INC 加1 - DEC 減1 - NEG 取負 - NOT 取補
二元操做
- ADD 加 - SUB 減 - IMUL 乘 - XOR 異或 - OR 或 - AND 與
注意操做的順序:
第二個操做數 操做符 第一個操做數
先給出移位量,第二項給出要移位的數值。
- SAL 左移 - SHL 左移(等同於SAL) - SAR 算術右移 - SHR 邏輯右移
目的操做數:一個寄存器或是一個存儲器位置。
乘積截斷
imull 雙操做數 - 從兩個32位操做數產生一個32位的乘積。
乘積不截斷
mull 無符號數乘法 imull 有符號數乘法 - 要求一個參數必須在寄存器%eax中,另外一個做爲指令的源操做數給出。 - 乘積的高32位在%edx中,低32位在%eax中。
有符號除法
idivl 操做數 - 將DX:AX中的64位數做爲被除數,操做數中爲除數 - 結果:商在AX中,餘數在DX中。
無符號除法
divl指令 - 一般會事先設定寄存器%edx爲0.
經常使用條件碼:
比較和測試指令:不修改任何寄存器的值,只設置條件碼
比較指令cmp和減法指令sub有何不一樣? - sub d,s 是d-s,結果送回d中,即送回目的操做數中。 - cmp d,s 也是d-s,但結果不送回目的操做數中,是利用減法進行兩個數值的比較。
根據條件碼的某個組合,將一個字節設置爲0或1。
SET指令:執行比較指令,根據計算t=a-b的結果設置條件碼
能夠有條件的傳送數據
間接跳轉:跳轉目標是從寄存器或存儲器位置中讀出的。
例: jmp *%eax 用寄存器%eax中的值做爲跳轉目標。 jmp *(%eax) 以%eax中的值做爲讀地址,從存儲器中讀出跳轉目標。
一些底層的機器指令有多個名字,條件跳轉只能是直接跳轉。
通用形式模板
if(test-expr) then-statement else else-statement (注:test-expr 整數表達式[假/真])
彙編實現形式
t = test-expr; if (!t) goto false; then-statement goto done; false: else-statement done:
通用形式:
do body-statement while(test-expr);
翻譯成以下條件和goto語句:
loop: body-statement t = test-expr; if(t) goto loop;
通用形式:
while (test-expr) body-statement
轉換成 do-while 形式:
if(!test-expr) goto done; do body-statement while(test-expr); done:
翻譯成 goto 形式:
t = test-expr; if(!t) goto done: loop: body-statement t = test-expr; if(t) goto loop; done:
通用形式
for(init-expr;test-expr;update-expr) body-statement
同 while:
init-expr; while(test-expr){ body-statement update-expr; }
對應 do-while 形式:
init-expr; if(!test-expr) goto done; do{ body-statement update-expr; }while(test-expr); done;
轉換成 goto 代碼:
init-expr t = test-expr; if(!t) goto done: loop: body-statement t = test-expr; if(t) goto loop; done:
棧幀: 爲單個過程分配的那部分棧
最頂端的棧幀以兩個指針界定:
- 寄存器%ebp爲幀指針 - 寄存器%esp爲棧指針
棧向低地址方向增加,棧指針%esp指向棧頂元素:
- 棧指針值適當減少能夠分配沒有指定初始值的數據的空間 - 相似的,能夠經過增長棧指針來釋放空間
支持過程調用和返回的指令:
效果:將返回地址入棧,並跳轉到被調用過程的起始處。
使用這個指令時,棧指針要指向前面call指令存儲返回地址的位置。
等價於:
movl %ebp,%esp popl %ebp
慣例:
- %eax,%edx,%ecx 劃分爲調用者保存寄存器 - %ebx,%esi,%edi 劃分爲被調用者保存寄存器 - %ebp,%esp 保持寄存器 - %eax 保存函數返回值
main函數保存%ebp,並設置新的幀指針。
pushl %ebp movl %esp,%ebp
分配4字節的棧空間
subl $4,%esp
設置 arg1=8
movl $8,(%esp)
將(%esp)中的8給 %eax,即存入棧中
movl %eax,(%esp)
將 %eax 與當即數 3 相加
add $3,%eax
在gh結束前彈棧
popl %ebp
main繼續 %eax 加1的操做
addl $1,%eax
leave爲返回準備棧,至關於%ebp出棧,最後ret結束。
參考資料1:深刻理解計算機系統(第二版)
參考資料2:教材導讀與每週考試重點---不斷更新
參考資料3:體系結構-指令集結構
參考資料4:函數調用過程棧幀變化詳解
參考資料5:彙編(五)——數據傳送指令一
參考資料6:彙編(八)——數據傳送類指令三
參考資料7:20135202閆佳歆——信息安全系統設計基礎第四周學習總結