從暫存器看I386和x64位中函式呼叫中引數傳遞

2021-06-22 03:57:15 字數 4027 閱讀 9600

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

intv1 = 1;

floatv2 = 0.01;

#ifdef fast

__attribute__((regparm(3)))

#endif

voidfunc(inta,longb,shortc,chard,longlonge,

floatf,doubleg,int*h,float*i,char*j)

intmain(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...