天天看點

資訊安全系統設計基礎第五周學習總結

實驗四 第三章 程式的機器級表示

本章學習内容是彙編語言,一定要能讀懂

3.1-3.7中練習重點:3.1,3.3,3.5,3.6,3.9,3.14,3.15,3.16,3.22,3.23,3.27,3.29,3.30,3.33,3.34

X86 尋址方式經曆三代:

1  DOS時代的平坦模式,不區分使用者空間和核心空間,很不安全
     2  8086的分段模式
     3  IA32的帶保護模式的平坦模式
           

對于機器級程式設計來說,其中兩種抽象尤為重要

1  機器級程式的格式和行為,定義為指令集體系結構(ISA),它定義了處理器狀态,指令的格式,以及每條指令對狀态的影響
     2  機器級程式使用的存儲器位址是虛拟位址,提供的存儲器模型看上去是一個非常大的位元組數組
           

資料格式:由于是從16位體系結構擴充成32位,intel用術語字(word)表示16位資料類型,是以32位為雙字(double words),64位數為4字(quad words)

對于ISA,要有以下基本觀念:IA32的ISA和x86-64的ISA,以及其他大多數ISA,在抽象時都将指令按順序執行抽象。但是處理器的硬體可以并發地執行許多指令,并且采用了一些safeguards來確定并行執行之後的結果和一條一條順序執行的結果一樣

一個IA32 CPU包含一組8個存儲32位值的寄存器,用以存整數資料和指針:eax,ecx,edx,ebx,esi,edi,esp,ebp.大多數情況下前六個都用作通用寄存器,eax,ecx,edx的存儲和恢複慣例不同于ebx,edi,esi(前三者為被調用者儲存,後三者為調用者儲存,詳見3.7.3);最後兩個用于存儲指針,由于在過進行中非常重要,分别指向棧幀的頂部和底部,必須保持

關于ISA的指令:

一是,ISA中每條指令占用位元組數不等,常用的指令所需的位元組數少,不太常用的指令的位元組數多,這樣的話,相對于每條指令占用等長位元組數的ISA,這種占用位元組數不等的ISA為程式産生的總空間要更少。

 二是,ISA中的指令在設計時,達到了一個效果,對于一個二進制指令串,從某個位元組開始,譯碼的結果是唯一的,這是達到了編碼理論中“唯一可譯性”的要求。

 (我覺得大概正是反彙編器正是利用了唯一可譯性,進而将一串指令位元組序列分割開來的)

 IA機器代碼和原始的C代碼差别很大

1  程式計數器(PC)指令将要執行的下一條指令在存儲器中的位址
     2  整數寄存器檔案包含8個命名的位置,分别存儲32位的值
     3  一些浮點寄存器存放浮點資料           

gcc -S xxx.c -o xxx.s 獲得彙編代碼,也可以用objdump -d xxx 反彙編

注意:  64位機器上想要得到32代碼:gcc -m32 -S xxx.c
       MAC OS中沒有objdump, 有個基本等價的指令otool 
       Ubuntu中 gcc -S code.c (不帶-O1) 産生的代碼更接近教材中代碼(删除"."開頭的語句)
           

二進制檔案可以用od 指令檢視,也可以用gdb的x指令檢視。 有些輸出内容過多,我們可以使用 more或less指令結合管道檢視,也可以使用輸出重定向來檢視

od code.o | more
            od code.o > code.txt
           

當一個源檔案生成了'.o'的目标二進制檔案後,無法直接檢視。

但是還是有個檢視目标代碼檔案内容的方法,就是對'.o'目标檔案使用反彙編器。它的輸出還是二進制檔案,但是,反彙編器将這些二進制按照指令進行了分段。讓我們知道哪一段是一個指令(格式上與彙編器産生的彙編檔案一樣,分行的)

表中不同資料的彙編代碼字尾

C聲明 Intel資料類型 彙編代碼字尾 位元組
char b 1
short w 2
int 雙字 l 4
long int
long long int ----- -
char *
float 單精度 s
double 雙精度 8
long double 擴充精度 t 10/12

資料傳送指令有三個變種:movb(傳送位元組)movw(傳送字)movl(傳送雙字)

寄存器:

     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位的不會發生溢出
           

操作數的三種類型:立即數、寄存器、存儲器

     立即數:即常數值

     寄存器:表示某個寄存器内容

     存儲器:根據計算出來的位址(通常稱有效位址)通路某個存儲器位置

     是以尋址方式也有多種,如:立即數尋址、寄存器尋址、絕對尋址、間接尋址、變址尋址、伸縮化  的變址尋址……

有效位址的計算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s

區分MOV,MOVS,MOVZ三個指令

     MOV相當于C語言的指派”=“

     MOVS将作了符号擴充的位元組傳送到字

     MOVZ将作了零擴充的位元組傳送到字

(不能從記憶體位址直接MOV到另一個記憶體位址,要用寄存器中轉一下)

mov族(mov指令還有很多兄弟指令如movb、movw、movsb、movzb)、pop、push

movsb、movzb分别為符号擴充、零擴充,它們隻拷貝一個位元組,源操作數均為單位元組,并設定目的操作數中其餘的位,效果如下:

      初始假設:%dh=8D  %eax=98765432

      1   movb   %dh,%al       ;%eax=9876548D

      2   movsbl %dh,%eax    ;%eax=FFFFFF8D(目的操作數高24位設為源位元組最高位,在這裡為很顯然為1,是以前24位為全F)

      3   movzbl %dh,%eax    ;%eax=0000008D(目的操作數高24位被設為0)

pushl指令等價于:

          subl $4,%esp

          movl %ebp,(%esp)  //注意這裡的括号引起的差别

popl指令等價于:

           movl (%esp),%eax

           addl $4,%esp

棧頂元素的位址是所有棧中元素位址中最低的

1.指針其實是位址,間接引用指針就是将該指針放在一個寄存器中 ,然後在間接存儲器引用中引用這個寄存器

2.局部變量通常儲存在寄存器中,而不是存儲器(個人猜測應該是局部變量屬于動态配置設定,局部變量是以被動态置入寄存器,而非存儲器)

例如調用exchange:

     int a = 4;

     int b = exchange(&a,3);

     printf("a=%d,b=%d\n",a,b);

     列印出a=3,b=4

(&(取址)建立一個指針,在本例中,該指針指向儲存局部變量a的位置.然後函數exchange用3覆寫存儲在a中的值,但是傳回4作為函數的值)

算術和邏輯操作

     移位操作 :sall==shll(填0)  sarl(算術右移,填符号位)  shrl(邏輯右移,填0)

     特殊算術操作:imull(有符号64位乘法)  mull(無符号64位乘法)  cltd(轉換為四字) idivl(有符号除法)   divl(無符号除法)

使用

gcc –S –o main.s main.c -m32

指令編譯成彙編代碼