2023关于浅谈C语言函数调用参数压栈相关问题(2023年)

时间:2023-02-19 09:15:33  来源:网友投稿

参数入栈的顺序以前在面试中被人问到这样的问题,函数调用的时候,参数入栈的顺序是从左向右,还是从右向左。参数的入栈顺序主要看调用方式,一般来说,__cdecl和__stdcall都是参数从右到左下面是小编为大家整理的2023关于浅谈C语言函数调用参数压栈相关问题(2023年),供大家参考。

2023关于浅谈C语言函数调用参数压栈相关问题(2023年)

  参数入栈的顺序

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

  看下面的代码:

  #includeint testint a, int b printf"address of a %x.n", &a; printf"address of b %x.n", &b; return 0;int main test1, 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 Addresspush arg1...push argnpush eippush ebp -- Low address

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

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

  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 test1, 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 8048414return 0; 804848a: b8 00 00 00 00 mov $0x0,%eaxint testint 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 8048340return 0; 8048466: b8 00 00 00 00 mov $0x0,%eaxUbuntu 64位反汇编:int main 40056e: 55 push %rbp 40056f: 48 89 e5 mov %rsp,%rbp test1, 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 40052dreturn 0; 400581: b8 00 00 00 00 mov $0x0,%eaxint testint 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 400410return 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 test1, 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 %rbp40052e: 48 89 e5 mov %rsp,%rbp400531: 48 83 ec 10 sub $0x10,%rsp400535: 89 7d fc mov %edi,-0x4%rbp400538: 89 75 f8 mov %esi,-0x8%rbp

推荐访问:浅谈 调用 函数 关于浅谈C语言函数调用参数压栈相关问题 关于浅谈c语言函数调用参数压栈的相关问题 c语言函数参数压栈顺序 简述函数调用时的压栈和出栈过程