C 反彙編學習筆記(一)

2022-09-05 19:09:11 字數 3449 閱讀 8449

chinese:

c++整數與浮點數的儲存方式

1、整數型別

無符號整數的所有位都用來表示數值,有符號整數的最高位是符號位,其餘位以補碼格式儲存。補碼規則就是用0減去這個數的絕對值(取反加一)。首先我們知道x+x(反碼)=0xffffffff, 因此x+x(反碼)+1=0, 因此x(補碼)=0-x=x(反碼)+1。補碼的好處就是方便計算機做加法。

2、浮點數型別

c++中的浮點數型別分為float和double,float佔4個位元組、double佔8個位元組。浮點數的操作不會用到通用暫存器,而是使用浮點協處理器的浮點暫存器。

浮點數的編碼方式採用的是ieee規定的編碼標準,float和double兩種型別的資料的轉換原理相同,不同的只是表示範圍。ieee規定的浮點數編碼會將乙個浮點數轉換成二進位制數。以科學計數法劃分,將浮點數拆分為3個部分:符號、指數、尾數。

float佔4個位元組,最高位是符號位,緊接著的8位表示指數,其餘位表示尾數。

例項分析:

(1) 12.25f 轉換成二進位制是1100.01,1100.01 = 1.10001 * 2 ^ 3。由於在二進位制中,尾數的最高位始終是1,所以忽略不計。因此尾數字是1000100000...剩下添0。指數部分有乙個規定,由於指數可能出現負數,十進位制的127表示為二進位制為01111111。ieee編碼方式規定,當指數域小於01111111時為乙個負數,反之為正數。因此01111111為0,所以指數字為3+127=130,二進位制為10000010。

符號位:0;指數字:10000010;尾數字:10000100000000000000000;表示成16進製為0x41440000

(2) -0.125f轉換成二進位制是-0.001,由於是負數所以符號位是1, 0.001=1.0 * 2 ^ -3,尾數最高位始終為1,所以忽略不計。尾數字是00000....,指數字是-3+127=124,二進位制是1111100。

符號位:1;指數字:01111100;尾數字:00000000000000000000000;表示成16進製為0xbe000000

(3)1.3f轉換成二進位制的時候,由於0.3轉換成二進位制會得到乙個無窮值: 0.3=0.25+0.03175+....,所以尾數字會捨棄多餘的部分。轉換成二進位制就約等於1.01001100110011001100110,到第23位終止。指數字為0+127,二進位制為01111111

符號位:0;指數字:01111111;尾數字:01001100110011001100110;表示成16進製為0x3fa66666

所以我們得出ieee編碼轉換後,得到的是乙個近似值,存在一定的誤差。所以這也就解釋了為何在c++判斷浮點數值是否為0時,要做乙個區間比較而不是直接進行等值比較。

float

fnum;

float fscope = 0.0001f

;if (fnum >= -fscope && fnum <=fscope)

3、double型別的ieee編碼

double型別和float型別大同小異,只是double型別表示的範圍更大,精度更高。最高位是符號位,指數字佔11位,尾數字佔42位。double擴大了精度,因此指數字需要加上1023,這些都可以推斷出來,這裡便不再贅述。

4、浮點數指令

浮點數的操作指令和普通資料型別不同,浮點數操作是通過浮點暫存器實現的,而普通資料型別是通過通用暫存器,它們使用的是兩套不同的指令。

浮點暫存器是通過棧結構來實現的,由st(0)~st(7)一共8個棧空間組成,每個浮點暫存器佔8個位元組。每次使用浮點暫存器都是率先壓入st(0),不能越過st(0)直接使用st(1),當8個暫存器都有資料時,此時再壓入資料的時候,st(7)的值會被丟棄。

整型資料與浮點型資料之間的相互轉換,來看一下反彙編出來的指令。

// c++ code:

float fnum = (float)argc;;

將位址ebp+8處的整型資料轉換成浮點型,並放入st(0)中,對應變數argc

fild dword ptr [ebp+8];

從st(0)中取出資料以浮點編碼方式存入位址ebp-4中,對應變數fnum

fst dword ptr [ebp-4

]// c++

code:

printf("%f

", fnum);

;這裡對esp執行減8操作是由於浮點數作為變參函式的引數時需要轉換為雙精度浮點值

;這步操作是提前準備8位元組的棧空間,以便存放double資料

sub esp,8

;將st(0)中的資料傳入esp中,並彈出st(0)

fstp

qword ptr [esp]

;以下為printf函式呼叫,略

push offset string "

%f" (0042302c

)call printf (0040e940

)add

esp, 0ch

// c++

code:

argc = (

int)fnum;

;將位址ebp-4處的資料以浮點型壓入st(0)中

fld dword ptr [ebp-4];

呼叫函式__ftol進行浮點數轉換

call __ftol (0040e688);

轉換後結果放入eax,並傳遞到ebp+8位址處

mov dword ptr[ [ebp+8

], eax

// c++

code:

printf("%d

", argc);

;略。。。

浮點數雖然佔4個位元組,但都是以8個位元組的方式進行處理。當浮點數作為引數時,不能直接壓棧。push指令只能傳入4位元組的資料到棧中,這樣會丟失4位元組的資料。所以使用printf以整數方式輸出浮點數時會產生錯誤。

浮點數作為返回值的彙編指令:

// c++ code:

fnum = getfloat();;

呼叫函式getfloat

call @ilt+5 (getfloat) (0040100a);

由於浮點數需要特殊處理,浮點數佔8位元組,無法使用eax進行傳遞

;使用浮點暫存器st(0)作為返回值

fst dword ptr [ebp-4

]// c++

code:

float getfloat()

;將浮點數儲存在st(0)中,在返回值為浮點數的情況下,無法使用eax

;使用st(0)作為返回值進行傳遞

fld dword ptr [__real@4@4002c400000000000000 (0042301c

)]ret

C 反彙編學習筆記(二)

chinese 1 位址 指標 引用 c 中位址標號用16進製表示,取乙個變數位址使用 操作符,只有變數才存在記憶體位址,常量沒有位址 不包括const定義的偽常量 指標是一種資料型別,用於儲存各種資料型別在記憶體中的位址。指標變數也可以取出位址,所以會出現多級指標。c 中引用不可以單獨定義,定義的...

學習筆記 2011 07 03 反彙編

include using namespace std int main 00c514e6 jmp main 27h 0c514a7h int a 0 00c514e8 mov dword ptr a 0 return 0 00c514ef xor eax,eax 00c514f1 pop edi ...

IDA反彙編學習(一)

toc c語言 if a b 彙編 mov eax,a cmp eax,b a b?jne l1 否 跳過後續指令 mov x,1 是,x,y 賦值 mov y,2 l1 對於迴圈語句,其實也是一樣的,也是通過跳轉指令來實現。c語言 while val1 val2 彙編 mov eax,val1 把...