发信人: feiy (积极、乐观、率性、自信), 信区: KernelTech
标 题: asmlinkage 其他 regparm attribute函数的gcc汇编浅析
发信站: BBS 水木清华站 (Mon Apr 26 02:56:12 2004), 转信
[asmlinkage 其他 regparm attribute函数的gcc汇编浅析]
asmlinkage是一类特殊的regparm attribute函数:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
下面的分析基于:c 源码 tt.c, 汇编代码 tt.S, shell命令是
gcc -S tt.c -o tt.S gcc version 3.2.2, cpu 386+
1. C 源码
01 | __attribute__((regparm(0~3))) int cal( int a, int b, int c, int d) |
02 | { |
03 | return a + b + c + d; |
04 | } |
05 | int main() |
06 | { |
07 | int r1=1; |
08 | int r2=2; |
09 | int r3=3; |
10 | int r4=4; |
11 |
12 | cal(r1, r2, r3, r4); |
13 |
14 | return 0; |
15 | } |
2. 当__attribute__((regparm(0))) int cal(int a, int b, int c, int d)
gcc编译得到下述汇编代码
01 | .file "tt.c" |
02 | .text |
03 | .globl cal |
04 | . type cal,@function |
05 | cal: |
06 | pushl % ebp |
07 | movl % esp , % ebp |
08 | movl 12(% ebp ), % eax # 从 堆栈 中取出传递给函数的第二个参数 b |
09 | addl 8(% ebp ), % eax # 从 堆栈 中取出传递给函数的第一个参数 a |
10 | addl 16(% ebp ), % eax # 从 堆栈 中取出传递给函数的第三个参数 c |
11 | addl 20(% ebp ), % eax # 从 堆栈 中取出传递给函数的第四个参数 d |
12 | leave |
13 | ret |
14 | .Lfe1: |
15 | . size cal,.Lfe1-cal |
16 | .globl main |
17 | . type main,@function |
18 | main: |
19 | pushl % ebp |
20 | movl % esp , % ebp |
21 | subl $24, % esp |
22 | andl $-16, % esp |
23 | movl $0, % eax |
24 | subl % eax , % esp |
25 | movl $1, -4(% ebp ) |
26 | movl $2, -8(% ebp ) |
27 | movl $3, -12(% ebp ) |
28 | movl $4, -16(% ebp ) |
29 | pushl -16(% ebp ) # 参数通过堆栈传递, 把要传递给函数的第四个参数压栈 |
30 | pushl -12(% ebp ) # 第三个参数入栈 注:这里的 ebp 用来指示main函数的局 |
31 | pushl -8(% ebp ) # 第二个参数入栈 部变量,-4(% ebp )存放的是第一 |
32 | pushl -4(% ebp ) # 第一个参数入栈 个局部变量r1,-4属于分配上的 |
33 | call cal # 巧合, 这里的-4与r1将作为传递给函 |
34 | # 数的第一个参数没有必然的关系。 |
35 | addl $16, % esp |
36 | movl $0, % eax |
37 | leave |
38 | ret |
39 | .Lfe2: |
40 | . size main,.Lfe2-main |
41 | .ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)" |
3. 当__attribute__((regparm(3))) int cal(int a, int b, int c, int d)
得到下述汇编代码
01 | .file "tt.c" |
02 | .text |
03 | .globl cal |
04 | . type cal,@function |
05 | cal: |
06 | pushl % ebp |
07 | movl % esp , % ebp |
08 | subl $12, % esp |
09 | movl % eax , -4(% ebp ) # 从 % eax 中取出传递给函数的第一个参数 a |
10 | movl % edx , -8(% ebp ) # 从 % edx 中取出传递给函数的第二个参数 b |
11 | movl % ecx , -12(% ebp ) # 从 % ecx 中取出传递给函数的第三个参数 c |
12 | movl -8(% ebp ), % eax |
13 | addl -4(% ebp ), % eax |
14 | addl -12(% ebp ), % eax |
15 | addl 8(% ebp ), % eax # 从 堆栈 中取出传递给函数的第四个参数 d |
16 | leave |
17 | ret |
18 | .Lfe1: |
19 | . size cal,.Lfe1-cal |
20 | .globl main |
21 | . type main,@function |
22 | main: |
23 | pushl % ebp |
24 | movl % esp , % ebp |
25 | subl $24, % esp |
26 | andl $-16, % esp |
27 | movl $0, % eax |
28 | subl % eax , % esp |
29 | movl $1, -4(% ebp ) |
30 | movl $2, -8(% ebp ) |
31 | movl $3, -12(% ebp ) |
32 | movl $4, -16(% ebp ) |
33 | subl $12, % esp |
34 | movl -12(% ebp ), % ecx # 通过 ecx 向函数传递第三个参数 r3 |
35 | movl -8(% ebp ), % edx # 通过 edx 向函数传递第二个参数 r2 |
36 | movl -4(% ebp ), % eax # 通过 eax 向函数传递第一个参数 r1 |
37 | pushl -16(% ebp ) # 通过 堆栈 向函数传递第四个参数 r4 |
38 | call cal |
39 | addl $16, % esp |
40 | movl $0, % eax |
41 | leave |
42 | ret |
43 | .Lfe2: |
44 | . size main,.Lfe2-main |
45 | .ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)" |
4. 结论
1) __attribute__((regparm(0~3))) 用来指定函数调用时通过寄存器传递参
数的个数
2) if any, 从第一个参数起, 依此通过 eax, edx, ecx 传递参数,
3) 而多出的参数将通过堆栈传递. 堆栈传递总是最后一个先入栈.