• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

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

c语言 搞代码 4年前 (2022-01-06) 28次浏览 已收录 0个评论

下面小编就为大家带来一篇浅谈C语言函数调用参数压栈的相关问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

参数入栈的顺序

以前在面试中被人问到这样的问题,函数调用的时候,参数入栈的顺序是从左向右,还是从右向左。参数的入栈顺序主要看调用方式,一般来说,__cdecl 和__stdcall 都是参数从右到左入栈。

看下面的代码:

 #include  int test(int a, int b) { printf("address of a %x.\n", &a); printf("address of b %x.\n", &b); return 0; } int main() { test(1, 2); return 0; }

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

 address of a 1ec62c. address of b 1ec628. 

32位Ubuntu的结果是:

 address of a bfd03290. address of b bfd03294. 

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

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

 typedef enum { LOW_TO_HIGH, HIGH_TO_LOW, LEFT_TO_RIGHT, RIGHT_TO_LEFT, }stack_direc_t; int stack_grow_direc() { static char *p = NULL; char c; if (p == NULL) { p = &c; stack_grow_direc(); } else { printf("First in stack address is %x.\n", p); printf("Second in stack address is %x.\n", &c); if (&c > p) { printf("Stack grows from low address to high address!\n"); return LOW_TO_HIGH; } else { printf("Stack grows from high address to low address!\n"); return HIGH_TO_LOW; } } }

函数调用时栈里都有什么

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

 push arg0 -- High Address push arg1 ... push argn push eip push ebp -- Low address

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

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

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

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

看下面的反汇编:

 C代码同上面一样 Ubuntu 32位反汇编: int main() { 804846d:  55           push  %ebp 804846e:  89 e5          mov  %esp,%ebp 8048470:  83 e4 f0        and  $0xfffffff0,%esp 8048473:  83 ec 10        sub  $0x10,%esp test(1, 2); 8048476:  c7 44 24 04 02 00 00  movl  $0x2,0x4(%esp) 804847d:  00 804847e:  c7 04 24 01 00 00 00  movl  $0x1,(%esp) 8048485:  e8 8a ff ff ff     call  8048414  return 0; 804848a:  b8 00 00 00 00     mov  $0x0,%eax } int test(int a, int b) { 8048414:  55           push  %ebp 8048415:  89 e5          mov  %esp,%ebp 8048417:  83 ec 18        sub  $0x18,%esp printf("address of a %x.\n", &a); 804841a:  b8 60 85 04 08     mov  $0x8048560,%eax 804841f:  8d 55 08        lea  0x8(%ebp),%edx 8048422:  89 54 24 04       mov  %edx,0x4(%esp) 8048426:  89 04 24        mov  %eax,(%esp) 8048429:  e8 12 ff ff ff     call  8048340  return 0; 8048466:  b8 00 00 00 00     mov  $0x0,%eax } Ubuntu 64位反汇编: int main() { 40056e:  55           push  %rbp 40056f:  48 89 e5        mov  %rsp,%rbp test(1, 2); 400572:  be 02 00 00 00     mov  $0x2,%esi 400577:  bf 01 00 00 00     mov  $0x1,%edi 40057c:  e8 ac ff ff ff     callq 40052d  return 0; 400581:  b8 00 00 00 00     mov  $0x0,%eax } int test(int a, int b) { 40052d:  55           push  %rbp 40052e:  48 89 e5        mov  %rsp,%rbp 400531:  48 83 ec 10       sub  $0x10,%rsp 400535:  89 7d fc        mov  %edi,-0x4(%rbp) 400538:  89 75 f8        mov  %esi,-0x8(%rbp) printf("address of a %x.\n", &a); 40053b:  48 8d 45 fc       lea  -0x4(%rbp),%rax 40053f:  48 89 c6        mov  %rax,%rsi 400542:  bf 14 06 40 00     mov  $0x400614,%edi 400547:  b8 00 00 00 00     mov  $0x0,%eax 40054c:  e8 bf fe ff ff     callq 400410  return 0; 400567:  b8 00 00 00 00     mov  $0x0,%eax }

看32位的ubuntu操作系统, 8048476: 的确是把参数直接入栈,2先入栈,1后入栈。

 8048476:  c7 44 24 04 02 00 00  movl  $0x2,0x4(%esp) 804847d:  00 804847e:  c7 04 24 01 00 00 00  movl  $0x1,(%esp) 8048485:  e8 8a ff ff ff     call  8048414 

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

 40056f:  48 89 e5        mov  %rsp,%rbp test(1, 2); 400572:  be 02 00 00 00     mov  $0x2,%esi 400577:  bf 01 00 00 00     mov  $0x1,%edi 40057c:  e8 ac ff ff ff     callq 40052d  

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

 40052d:  55           push  %rbp 40052e:  48 89 e5        mov  %rsp,%rbp 400531:  48 83 ec 10       sub  $0x10,%rsp 400535:  89 7d fc        mov  %edi,-0x4(%rbp) 400538:  89 75 f8        mov  %esi,-0x8(%rbp)

以上就是小编为大家带来的浅谈C语言函数调用参数压栈的相关问题的全部内容了,希望对大家有所帮助,多多支持gaodaima搞代码网~

以上就是浅谈C语言函数调用参数压栈的相关问题的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:浅谈C语言函数调用参数压栈的相关问题

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址