c++ - 函数调用时入栈参数与局部变量在栈中地址问题
PHP中文网
PHP中文网 2017-04-17 15:39:09
0
2
813
#include <iostream>



int foo(int a, int b, int c, int d) {

  int e;

  int f;

  std::cout << std::hex;

  std::cout << "Address of a: " << &a << std::endl;

  std::cout << "Address of b: " << &b << std::endl;

  std::cout << "Address of c: " << &c << std::endl;

  std::cout << "Address of d: " << &d << std::endl;

  std::cout << "Address of e: " << &e << std::endl;

  std::cout << "Address of f: " << &f << std::endl;

  return a + b + c + d;

} 



int main() {


  foo(4, 2, 3, 4);

  return 0;

}

输出:
gcc 4.9.2 -32bit release:
Address of a: 0x6efea0
Address of b: 0x6efea4
Address of c: 0x6efea8
Address of d: 0x6efeac
Address of e: 0x6efe8c
而就我目前的知识了解,栈是从高地址到底地址存储数据,而读取参数的顺序为从右到左,以第一次函数调用为例,入栈顺序应该是:d-c-b-a之后是按顺序将局部变量入栈,即e-f,但是比较e和a的地址可以发现二者在32位下相差14个字节,在64位下相差36个字节,感到比较奇怪,按之前看到的文章:http://blog.csdn.net/tdgx2004...,在局部变量与参数之间应该是函数地址与保护栈底(32位下8个字节),但是实际情况是14个字节,非常好奇还有6个字节装的是什么?
求教大神们。
下面是foo函数的汇编:
foo(int,int,int,int)

   0x00401500 <+0>:    push   %ebp
   0x00401501 <+1>:    mov    %esp,%ebp
   0x00401503 <+3>:    sub    $0x28,%esp
   0x00401506 <+6>:    movl   $0x479590,(%esp)
   0x0040150d <+13>:    mov    $0x488140,%ecx
   0x00401512 <+18>:    call   0x451580 <_ZNSolsEPFRSt8ios_baseS0_E>
   0x00401517 <+23>:    sub    $0x4,%esp
   0x0040151a <+26>:    movl   $0x489000,0x4(%esp)
   0x00401522 <+34>:    movl   $0x488140,(%esp)
   0x00401529 <+41>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x0040152e <+46>:    lea    0x8(%ebp),%ecx
   0x00401531 <+49>:    mov    %ecx,(%esp)
   0x00401534 <+52>:    mov    %eax,%ecx
   0x00401536 <+54>:    call   0x4515c0 <_ZNSolsEPKv>
   0x0040153b <+59>:    sub    $0x4,%esp
   0x0040153e <+62>:    movl   $0x4795c0,(%esp)
   0x00401545 <+69>:    mov    %eax,%ecx
   0x00401547 <+71>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x0040154c <+76>:    sub    $0x4,%esp
   0x0040154f <+79>:    movl   $0x48900f,0x4(%esp)
   0x00401557 <+87>:    movl   $0x488140,(%esp)
   0x0040155e <+94>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x00401563 <+99>:    mov    %eax,%edx
   0x00401565 <+101>:    lea    0xc(%ebp),%eax
   0x00401568 <+104>:    mov    %eax,(%esp)
   0x0040156b <+107>:    mov    %edx,%ecx
   0x0040156d <+109>:    call   0x4515c0 <_ZNSolsEPKv>
   0x00401572 <+114>:    sub    $0x4,%esp
   0x00401575 <+117>:    movl   $0x4795c0,(%esp)
   0x0040157c <+124>:    mov    %eax,%ecx
   0x0040157e <+126>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x00401583 <+131>:    sub    $0x4,%esp
   0x00401586 <+134>:    movl   $0x48901e,0x4(%esp)
   0x0040158e <+142>:    movl   $0x488140,(%esp)
   0x00401595 <+149>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x0040159a <+154>:    mov    %eax,%edx
   0x0040159c <+156>:    lea    0x10(%ebp),%eax
   0x0040159f <+159>:    mov    %eax,(%esp)
   0x004015a2 <+162>:    mov    %edx,%ecx
   0x004015a4 <+164>:    call   0x4515c0 <_ZNSolsEPKv>
   0x004015a9 <+169>:    sub    $0x4,%esp
   0x004015ac <+172>:    movl   $0x4795c0,(%esp)
   0x004015b3 <+179>:    mov    %eax,%ecx
   0x004015b5 <+181>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x004015ba <+186>:    sub    $0x4,%esp
   0x004015bd <+189>:    movl   $0x48902d,0x4(%esp)
   0x004015c5 <+197>:    movl   $0x488140,(%esp)
   0x004015cc <+204>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x004015d1 <+209>:    mov    %eax,%edx
   0x004015d3 <+211>:    lea    0x14(%ebp),%eax
   0x004015d6 <+214>:    mov    %eax,(%esp)
   0x004015d9 <+217>:    mov    %edx,%ecx
   0x004015db <+219>:    call   0x4515c0 <_ZNSolsEPKv>
   0x004015e0 <+224>:    sub    $0x4,%esp
   0x004015e3 <+227>:    movl   $0x4795c0,(%esp)
   0x004015ea <+234>:    mov    %eax,%ecx
   0x004015ec <+236>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x004015f1 <+241>:    sub    $0x4,%esp
   0x004015f4 <+244>:    movl   $0x48903c,0x4(%esp)
   0x004015fc <+252>:    movl   $0x488140,(%esp)
   0x00401603 <+259>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x00401608 <+264>:    mov    %eax,%edx
   0x0040160a <+266>:    lea    -0xc(%ebp),%eax
   0x0040160d <+269>:    mov    %eax,(%esp)
   0x00401610 <+272>:    mov    %edx,%ecx
   0x00401612 <+274>:    call   0x4515c0 <_ZNSolsEPKv>
   0x00401617 <+279>:    sub    $0x4,%esp
   0x0040161a <+282>:    movl   $0x4795c0,(%esp)
   0x00401621 <+289>:    mov    %eax,%ecx
   0x00401623 <+291>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x00401628 <+296>:    sub    $0x4,%esp
   0x0040162b <+299>:    movl   $0x48904b,0x4(%esp)
   0x00401633 <+307>:    movl   $0x488140,(%esp)
   0x0040163a <+314>:    call   0x47b500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
   0x0040163f <+319>:    mov    %eax,%edx
   0x00401641 <+321>:    lea    -0x10(%ebp),%eax
   0x00401644 <+324>:    mov    %eax,(%esp)
   0x00401647 <+327>:    mov    %edx,%ecx
   0x00401649 <+329>:    call   0x4515c0 <_ZNSolsEPKv>
   0x0040164e <+334>:    sub    $0x4,%esp
   0x00401651 <+337>:    movl   $0x4795c0,(%esp)
   0x00401658 <+344>:    mov    %eax,%ecx
   0x0040165a <+346>:    call   0x451570 <_ZNSolsEPFRSoS_E>
   0x0040165f <+351>:    sub    $0x4,%esp
   0x00401662 <+354>:    mov    0x8(%ebp),%edx
   0x00401665 <+357>:    mov    0xc(%ebp),%eax
   0x00401668 <+360>:    add    %eax,%edx
   0x0040166a <+362>:    mov    0x10(%ebp),%eax
   0x0040166d <+365>:    add    %eax,%edx
   0x0040166f <+367>:    mov    0x14(%ebp),%eax
   0x00401672 <+370>:    add    %edx,%eax
=> 0x00401674 <+372>:    leave  
   0x00401675 <+373>:    ret    
PHP中文网
PHP中文网

认证0级讲师

reply all(2)
阿神

LZ, you’d better put a piece of your assembly code and just add -S when compiling.
I ran your code and my output is as follows:

Address of a: 0x7fff3e06b44c
Address of b: 0x7fff3e06b448
Address of c: 0x7fff3e06b444
Address of d: 0x7fff3e06b440
Address of e: 0x7fff3e06b45c
Address of f: 0x7fff3e06b458

The difference between e and a is 0x10, which is 16 in decimal.

I used your code to generate a piece of assembly, and found that the parameters of foo() were not pushed onto the stack. Instead, the parameters were given to register first, and then the register value was stored in the stack, so it is similar to your situation. Different, you can see that the address of a is higher than that of d, and the addresses of these parameters are smaller than the local variables.

.globl main
    .type    main, @function
main:
.LFB958:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    , %ecx
    movl    , %edx
    movl    , %esi
    movl    , %edi
    call    _Z3fooiiii
    movl    
.LC0:
    .string    "Address of a: "
.LC1:
    .string    "Address of b: "
.LC2:
    .string    "Address of c: "
.LC3:
    .string    "Address of d: "
.LC4:
    .string    "Address of e: "
.LC5:
    .string    "Address of f: "
    .text
.globl _Z3fooiiii
    .type    _Z3fooiiii, @function
_Z3fooiiii:
.LFB957:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    , %rsp
    movl    %edi, -20(%rbp)
    movl    %esi, -24(%rbp)
    movl    %edx, -28(%rbp)
    movl    %ecx, -32(%rbp)
    movl    $_ZSt3hexRSt8ios_base, %esi
    movl    $_ZSt4cout, %edi
    call    _ZNSolsEPFRSt8ios_baseS0_E
    movl    $.LC0, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -20(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    $.LC1, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -24(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    $.LC2, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -28(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    $.LC3, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -32(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    $.LC4, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -4(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    $.LC5, %esi
    movl    $_ZSt4cout, %edi
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    leaq    -8(%rbp), %rdx
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    _ZNSolsEPKv
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    movq    %rax, %rdi
    call    _ZNSolsEPFRSoS_E
    movl    -20(%rbp), %edx
    movl    -24(%rbp), %eax
    addl    %eax, %edx
    movl    -28(%rbp), %eax
    addl    %eax, %edx
    movl    -32(%rbp), %eax
    leal    (%rdx,%rax), %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc
rrreee
迷茫

This problem is related to the platform, the calling convention adopted, and the compiler.
i386 platform, under the default _cdecl calling convention, on the runtime stack, between function parameters and function local variables are 1: return address (pc after call instruction), 2: caller’s stack frame base address ( ebp), 3: callee save registers (the number is different on different platforms), 4: information added to the stack in order to handle exceptions (different compilers may implement different things, gcc will add things)

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template