彙編角度看C語言資料型別
1、什麼是裸函式?
void __declspec(naked) Function()
{...}
上面的函式呼叫時,為什麼會出錯?
void __declspec(naked) Function()
{
__asm ret
}
2、無引數無返回值的函式框架
void __declspec(naked) Function()
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
3、有引數有返回值的函式框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov eax,dword ptr ds:[ebp+8]
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
4、帶區域性變數的函式框架
int __declspec(naked) Function(int x,int y)
{
__asm
{
push ebp
mov ebp,esp
sub esp,0x40
push ebx
push esi
push edi
lea edi,dword ptr ds:[ebp-0x40]
mov eax,0xCCCCCCCC
mov ecx,0x10
rep stosd
mov dword ptr ds:[ebp-4],2
mov dword ptr ds:[ebp-8],3
mov eax,dword ptr ds:[ebp+8]
add eax,dword ptr ds:[ebp+0xC]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
}
}
常見的幾種呼叫約定:
呼叫約定 引數壓棧順序 平衡堆疊
__cdecl 從右至左入棧 呼叫者清理棧
__stdcall 從右至左入棧 自身清理堆疊
__fastcall ECX/EDX傳送前兩個 自身清理堆疊
剩下:從右至左入棧
1、int __cdecl Plus(int a, int b) { return a+b; } push 2 push1 call @ILT+15(Plus) (00401014) add esp,8
2、int __stdcall Plus(int a, int b) { return a+b; } push 2 push 1 call @ILT+10(Plus) (0040100f)
函式內部:
ret 8
3、int __fastcall Plus(inta, int b) { return a+b; } mov edx,2 mov ecx,1 call @ILT+0(Plus) (00401005)
函式內部:
ret 4、int __fastcall Plus4(int a, int b,int c,int d) { return a+b+c+d; } push 4 push 3 mov edx,2 mov ecx,1 call @ILT+5(Plus) (0040100a)
函式內部:
ret 8
1、C語言中的資料型別:
整數型別
基本型別
浮點型別
陣列型別
C語言資料型別 構造型別 結構體型別
共用體(聯合)型別
指標型別
空型別(void)
2、學習資料型別的三個要素:
1、儲存資料的寬度
2、儲存資料的格式
3、作用範圍(作用域)
3、整數型別:char short int long
在反彙編中觀察,體驗資料寬度的概念
char 8BIT 1位元組 char cTemp = 0xFF;
short sTemp = 0xFF;
short 16BIT 2位元組 int nTemp = 0xFF;
int 32BIT 4位元組 char cTemp = 0x12345678;
short sTemp = 0x12345678;
long 32BIT 4位元組 int nTemp = 0x12345678;
整數型別分為有符號(signed)和無符號(unsigned)兩種:
char cTest = 0xFF; unsigned char i = 0xFF;
unsigned char j = 0x1;
unsigned char cuTest = 0xFF;
if(i>j)
printf("%d\n%d",cTest,cuTest); {
printf("i>j");
總結: }
else
1、在記憶體中儲存的方式完全一樣 {
printf("i<j");
2、在做運算的時候需要注意 }
4、浮點型別:float double
float和double在儲存方式上都是遵從IEEE的規範的
float的儲存方式如下圖所示:
31 30 22 0
1 8 23
符號位 指數部分 尾數部分
8.4
double的儲存方式如下圖所示:
63 62 51 0
1 11 52
符號位 指數部分 尾數部分
將一個float型轉化為記憶體儲存格式的步驟為:
1、先將這個實數的絕對值化為二進位制格式
2、將這個二進位制格式實數的小數點左移或右移n位,直到小數點移動到第一個有效數字的右邊。
3、從小數點右邊第一位開始數出二十三位數字放入第22到第0位。
4、如果實數是正的,則在第31位放入“0”,否則放入“1”。
5、如果n 是左移得到的,說明指數是正的,第30位放入“1”。如果n是右移得到的或n=0,則第30位放入“0”。
6、如果n是左移得到的,則將n減去1後化為二進位制,並在左邊加“0”補足七位,放入第29到第23位。
如果n是右移得到的或n=0,則將n化為二進位制後在左邊加“0”補足七位,再各位求反,再放入第29到第23位。
舉例說明:
8.25轉成浮點儲存
整數部分8轉成2進位制
8/2 = 4 0
4/2 = 2 0
2/2 = 1 0
1/2 = 0 1
3 - 1 = 2 10
小數部分0.25轉成二進位制:
Float = 6
0.25*2 = 0.5 0
0.5*2 = 1.0 1 1 8 23
0 10000010 00001000000000000000000
8.25用二進位制表示可表示為1000.01
1000.01 = 1.00001 *2的3次方 小數點向左移動3位 指數為3
1 10000010 00001000000000000000000 0100 0001 0000 0100 0000 0000 0000 0000 = 41040000
41040000
-8.25轉成浮點數是多少呢? 1100 0001 0000 0100 0000 0000 0000 0000 = C1040000
C1040000
0.25轉成浮點儲存
整數部分0 0
0.25 * 2 = 0.5 0
0.5*2 = 1.0 1
0.01 = 1.0 * 2的2次方 右移動 注意:向右移動2個位 指數為-2
0 01111101 00000000000000000000000
5、英文字元儲存
char x = 'A';
char y = 65;
A 10101
參見ASCII編碼 B 11111
C 11110
, 101011
6、中文字元儲存
char* x = "啊";
char* y = "北";
參見GB2312-80編碼
這種編碼儲存在的問題