x86_64基本使用暫存器儲存函式引數,暫存器不夠才入棧;
而i386將所有引數儲存在棧上,通過gcc的擴充套件功能__attribute__((regparm()))即可實現部分引數的暫存器傳遞。**1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include
#include
int
v1 = 1;
float
v2 = 0.01;
#ifdef fast
__attribute__((regparm(3)))
#endif
void
func(
int
a,
long
b,
short
c,
char
d,
long
long
e,
float
f,
double
g,
int
*h,
float
*i,
char
*j)
int
main(
void
)
編譯gcc -g -wall -o test test.c
啟動gdb
(gdb) b * func
說明:break中不加* 使用函式名就無法用於引數確認
不加*,斷點就不會設定到組合語言層級的函式開頭
在i386上原則上引數全部入棧,取得第乙個引數使用esp+4,因為i386架構中棧的開頭即esp+0,儲存返回位址。
i386暫存器呼叫
fastcall快速呼叫:i386像x86_64一樣將部分引數放暫存器中。
__attribute__((regparm(3)))使用eax,edx和ecx傳遞開頭3個引數。
修改**
第1,2,3個引數a ,b,c放在eax,edx,ecx中。
如果第1個引數為long long型別(64位),那麼就會組合使用eax ,edx 等暫存器來傳參。
如果第2個引數為long long型別(64位),那麼就只有在第乙個引數為32位才能暫存器傳遞。
regparm
gcc中可以使用__attribute__((regparm(n)))指定最多可以使用n個暫存器(eax, edx, ecx)傳遞引數,n的範圍是0~3,超過n時則將引數壓入棧中(n=0表示不用暫存器傳遞引數)。
看下面例子,函式p1約定不使用暫存器傳遞引數,儘管只有1個引數,仍然將引數壓入棧中。
函式p2約定最多可使用3個暫存器傳遞引數,因為輸入引數有4個,所以前三個使用暫存器傳遞,最後乙個壓入棧中。
int q = 5;
int t1 = 1;
int t2 = 2;
int t3 = 3;
int t4 = 4;
#define regparm3 __attribute((regparm(3)))
#define regparm0 __attribute((regparm(0)))
void regparm0 p1(int a)
void regparm3 p2(int a, int b, int c, int d)
同樣的**我們看64位下的效果
i386 ABI之暫存器保護規則
一 保護原則 被作為函式返回值。對於呼叫者來說,如果在呼叫後必須用到呼叫前的eax的值,則呼叫者必須自己事先儲存eax,即使被呼叫函式沒有返回值也必須遵守這個原則。而對於被呼叫函式,可以隨意的使用eax,不需要對其作任何保護。2.ebx 對於位址無關 position independent cod...
i386和X86各是什麼意思
ia32 32 bits intel architecture 32位頻寬intel構架 ia64 64 bits intel architecture 64位頻寬intel構架 i386 intel 386 老的386機器,也泛指ia32體系的cpu i486 intel 486 i586 int...
作業系統的i386 和x86的區別
x86 包含 i386 i386 僅僅是 x86 的一部分。x86 這裡的 x 本來就是乙個未知數性質的,他可以是 3 4 5 6 7 x86 是 intel 建立起來的 cpu 架構。他的 8086 8088 80286 80386 80486 pentium pentium pro pentiu...