程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺談C說話函數挪用參數壓棧的相干成績

淺談C說話函數挪用參數壓棧的相干成績

編輯:關於C++

淺談C說話函數挪用參數壓棧的相干成績。本站提示廣大學習愛好者:(淺談C說話函數挪用參數壓棧的相干成績)文章只能為提供參考,不一定能成為您想要的結果。以下是淺談C說話函數挪用參數壓棧的相干成績正文


參數入棧的次序

之前在面試中被人問到如許的成績,函數挪用的時刻,參數入棧的次序是從左向右,照樣從右向左。參數的入棧次序重要看挪用方法,普通來講,__cdecl 和__stdcall 都是參數從右到左入棧。

看上面的代碼:

#include <stdio.h>

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位體系也是一樣,沒有甚麼分歧,如今歸結起來有兩點:

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 <test>
  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 <printf@plt>

  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 <test>
  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 <printf@plt>

  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 <test>

再來看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 <test>

再來看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說話函數挪用參數壓棧的相干成績的全體內容了,願望對年夜家有所贊助,多多支撐~

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved