C语言函数调用参数压栈的相关问题.docx

上传人:b****6 文档编号:7269970 上传时间:2023-01-22 格式:DOCX 页数:13 大小:16.38KB
下载 相关 举报
C语言函数调用参数压栈的相关问题.docx_第1页
第1页 / 共13页
C语言函数调用参数压栈的相关问题.docx_第2页
第2页 / 共13页
C语言函数调用参数压栈的相关问题.docx_第3页
第3页 / 共13页
C语言函数调用参数压栈的相关问题.docx_第4页
第4页 / 共13页
C语言函数调用参数压栈的相关问题.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

C语言函数调用参数压栈的相关问题.docx

《C语言函数调用参数压栈的相关问题.docx》由会员分享,可在线阅读,更多相关《C语言函数调用参数压栈的相关问题.docx(13页珍藏版)》请在冰豆网上搜索。

C语言函数调用参数压栈的相关问题.docx

C语言函数调用参数压栈的相关问题

参数入栈的顺序

以前在面试中被人问到这样的问题,函数调用的时候,参数入栈的顺序是从左向右,还是从右向左。

参数的入栈顺序主要看调用方式,一般来说,__cdecl和__stdcall都是参数从右到左入栈。

看下面的代码:

#include

inttest(inta,intb)

{

printf("addressofa%x.\n",&a);

printf("addressofb%x.\n",&b);

return0;

}

intmain()

{

test(1,2);

return0;

}

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

在64位Ubuntu的系统下的运行结果是:

addressofa1ec62c.

addressofb1ec628.

32位Ubuntu的结果是:

addressofabfd03290.

addressofbbfd03294.

可以看出,首先,不同的体系结构,栈增长的方向也不同,有的是从低地址向高地址方向增长,有的是从高地址向低地址方向增长。

可以用以下的代码来判断栈的增长方向:

typedefenum{

LOW_TO_HIGH,

HIGH_TO_LOW,

LEFT_TO_RIGHT,

RIGHT_TO_LEFT,

}stack_direc_t;

intstack_grow_direc()

{

staticchar*p=NULL;

charc;

if(p==NULL){

p=&c;

stack_grow_direc();

}

else{

printf("Firstinstackaddressis%x.\n",p);

printf("Secondinstackaddressis%x.\n",&c);

if(&c>p){

printf("Stackgrowsfromlowaddresstohighaddress!

\n");

returnLOW_TO_HIGH;

}

else{

printf("Stackgrowsfromhighaddresstolowaddress!

\n");

returnHIGH_TO_LOW;

}

}

}

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

∙15

∙16

∙17

∙18

∙19

∙20

∙21

∙22

∙23

∙24

∙25

∙26

∙27

∙28

∙29

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

∙15

∙16

∙17

∙18

∙19

∙20

∙21

∙22

∙23

∙24

∙25

∙26

∙27

∙28

∙29

函数调用时栈里都有什么

以参数从左到右入栈为例:

pusharg0--HighAddress

pusharg1

...

pushargn

pusheip

pushebp--Lowaddress

∙1

∙2

∙3

∙4

∙5

∙6

∙1

∙2

∙3

∙4

∙5

∙6

32位系统和64位系统函数调用时,参数入栈方式有不同么?

这个问题在不久之前被人问题,当时傻了,我一直以来只关注过32位系统的参数入栈方式,一直以为64位系统也是一样,没有什么不同,现在归纳起来有两点:

∙64位系统先把传入参数放在寄存器里面,在被调函数的具体实现中把寄存器的值入栈,然后再去栈中取参数

∙64位系统栈中参数存放的顺序是从左至右的(因为先经历了寄存器传值)

看下面的反汇编:

C代码同上面一样

Ubuntu32位反汇编:

intmain()

{

804846d:

55push%ebp

804846e:

89e5mov%esp,%ebp

8048470:

83e4f0and$0xfffffff0,%esp

8048473:

83ec10sub$0x10,%esp

test(1,2);

8048476:

c7442404020000movl$0x2,0x4(%esp)

804847d:

00

804847e:

c7042401000000movl$0x1,(%esp)

8048485:

e88affffffcall8048414

return0;

804848a:

b800000000mov$0x0,%eax

}

inttest(inta,intb)

{

8048414:

55push%ebp

8048415:

89e5mov%esp,%ebp

8048417:

83ec18sub$0x18,%esp

printf("addressofa%x.\n",&a);

804841a:

b860850408mov$0x8048560,%eax

804841f:

8d5508lea0x8(%ebp),%edx

8048422:

89542404mov%edx,0x4(%esp)

8048426:

890424mov%eax,(%esp)

8048429:

e812ffffffcall8048340

return0;

8048466:

b800000000mov$0x0,%eax

}

Ubuntu64位反汇编:

intmain()

{

40056e:

55push%rbp

40056f:

4889e5mov%rsp,%rbp

test(1,2);

400572:

be02000000mov$0x2,%esi

400577:

bf01000000mov$0x1,%edi

40057c:

e8acffffffcallq40052d

return0;

400581:

b800000000mov$0x0,%eax

}

inttest(inta,intb)

{

40052d:

55push%rbp

40052e:

4889e5mov%rsp,%rbp

400531:

4883ec10sub$0x10,%rsp

400535:

897dfcmov%edi,-0x4(%rbp)

400538:

8975f8mov%esi,-0x8(%rbp)

printf("addressofa%x.\n",&a);

40053b:

488d45fclea-0x4(%rbp),%rax

40053f:

4889c6mov%rax,%rsi

400542:

bf14064000mov$0x400614,%edi

400547:

b800000000mov$0x0,%eax

40054c:

e8bffeffffcallq400410

return0;

400567:

b800000000mov$0x0,%eax

}

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

∙15

∙16

∙17

∙18

∙19

∙20

∙21

∙22

∙23

∙24

∙25

∙26

∙27

∙28

∙29

∙30

∙31

∙32

∙33

∙34

∙35

∙36

∙37

∙38

∙39

∙40

∙41

∙42

∙43

∙44

∙45

∙46

∙47

∙48

∙49

∙50

∙51

∙52

∙53

∙54

∙55

∙56

∙57

∙58

∙59

∙60

∙1

∙2

∙3

∙4

∙5

∙6

∙7

∙8

∙9

∙10

∙11

∙12

∙13

∙14

∙15

∙16

∙17

∙18

∙19

∙20

∙21

∙22

∙23

∙24

∙25

∙26

∙27

∙28

∙29

∙30

∙31

∙32

∙33

∙34

∙35

∙36

∙37

∙38

∙39

∙40

∙41

∙42

∙43

∙44

∙45

∙46

∙47

∙48

∙49

∙50

∙51

∙52

∙53

∙54

∙55

∙56

∙57

∙58

∙59

∙60

看32位的ubuntu操作系统,8048476:

的确是把参数直接入栈,2先入栈,1后入栈。

8048476:

c7442404020000movl$0x2,0x4(%esp)

804847d:

00

804847e:

c7042401000000movl$0x1,(%esp)

8048485:

e88affffffcall8048414

∙1

∙2

∙3

∙4

∙1

∙2

∙3

∙4

再来看64位的ubuntu操作系统,2和1根本就没有放入到栈中,而是放到了寄存器esi和edi中。

40056f:

4889e5mov%rsp,%rbp

test(1,2);

400572:

be02000000mov$0x2,%esi

400577:

bf01000000mov$0x1,%edi

40057c:

e8acffffffcallq40052d

∙1

∙2

∙3

∙4

∙5

∙1

∙2

∙3

∙4

∙5

再来看64位系统test的实现,先把edi入栈,再把esi入栈,这就是为什么函数看起来像是从左到右入栈的原因了。

40052d:

55push%rbp

40052e:

4889e5mov%rsp,%rbp

400531:

4883ec10sub$0x10,%rsp

400535:

897dfcmov%edi,-0x4(%rbp)

400538:

8975f8mov%esi,-0x8(%rbp)

∙1

∙2

∙3

∙4

∙5

∙1

∙2

∙3

∙4

∙5

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1