精华内容
下载资源
问答
  • 我的意思是 如果有两次调用一个函数 他们的变量所在的位置是一样的 那么 果然 上图 2.残局值 我猜 如果上一次将某个函数区值 赋成一个固定值 下次 “偶然”获得那个内存块的还是:上一世的值 额 有点怪...

    1.如果我没参错的 话 在一个程序 运行时参数栈的大小就确定了  然后以后函数就一直用那个栈了

    我的意思是 如果有两次调用一个函数 他们的变量所在的位置是一样的 那么

    果然 上图

     

     

    2.残局值 我猜 如果上一次将某个函数栈区值 赋成一个固定值 下次 “偶然”获得那个内存块的还是:上一世的值

    额 有点怪 

    PS在这之前插播一下 哈 argv

    每一个指针都指向了一个char OS文件管理就是按名存取吗 意思是

    反正就这样

    WinMain也差不多

    OK接上

    我想返回 GY2()函数栈的栈底的变量的地址 然后从外部给他一个值 然后在调用看看 值是否与我们赋值的一样

    但不是这样的

     

    在执行到这一步时 我们目的确实达到了

     

    但在往下 在 就被神秘力量改变了啊啊啊啊

    算了 不管了 至少 函数栈的地址 是固定的

    //

    全局变量的好处 

    我们如果想一个在多个函数都用到的 资源变量 那最好别再函数里 因为他会在函数栈里是不暴露的

    除非传值 但参数入栈 是耗时间的 对游戏来说 我们要的是效率 所以别整花里胡哨的 即便你在函数里

    用指针 申请了 一个堆区空间 但在别的函数里用时 那块空间没有指针相当于“失踪了”没有他的联系方式

    所以也要传指针 

    而且局部变量的生命在函数结束每一次调用后就会GG 

    展开全文
  • 函数调用栈过程

    2019-01-31 19:27:42
    本文分析函数的调用过程中,的变化过程。

    本文分析函数的调用过程中,栈的变化过程。

    X86寄存器简介

    寄存器名称 注释
    eax 累加器,是很多加法、乘法的默认寄存器
    ebx 基地址,内存寻址时,存放基地址
    ecx 计数器,是重复前缀指令和LOOP指令的内定计数器
    edx 存放整数除法产生的余数
    esi 源索引寄存器,因为在很多字符串操作指令中,DS:ESI指向源串,而ES:EDI指向目标串
    ebp 基址指针,常被用作高级语言函数调用时的“帧指针”(frame pointer)
    esp 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。

    文章常用汇编指令的理解

    0x4(%esp)
    

    把寄存器esp中的值取出,然后加上4,得到的值作为地址,间接寻址得到需要的数据
    例如,

    pushl -0x4(%ecx)
    

    该指令的含义是取出寄存器ecx的值,减去4,将得到的值作为地址,在内存找到该地址对应的值,将其压入栈中。

    lea 0x4(%esp), %ecx
    

    该指令的作用是,取出esp寄存器里的值,加上4,不再继续寻址,而是将得到值直接传递给ecx;如果是其他指令,则还需进行间接寻址,再传值。

    call
    

    首先将eip设置为本函数中call后的那条指令的地址(所有指令都有这步)。然后push %eip。(esp自减4,将eip的值存入esp指向的地址,最后子函数ebp+4出即存储了这一步保存的eip值)。然后将eip的值设置为被调用函数的第一调指令的地址。(最后cpu继续执行eip所指向地址的指令,虽然这不是call干的事)

    leave
    

    首先将esp指向ebp。然后pop %ebp.(将esp指向内存的值拷到ebp,esp自减4)。

    ret
    

    pop%eip(即先将esp指向的内存块的值拷贝到eip中,然后esp自减4)

    函数栈帧结构

    Figure 15-5-2

    举例演示

    简单的源代码:

    #include<stdio.h>

    int sum(int x, int y)
    {
        int tmp = 0;
        
        tmp = x+y;
        return tmp;
    }
     
    int main()
    {
        int a=10;
        int b=20;
        int ret=0;
     
        ret=sum(a,b);
        printf("ret=%d\n",ret);
        return 0;
    }
    

    利用反汇编工具 objdump 将执行文件生成汇编文件,其内容如下:

    ......
    0804840b <sum>:
     804840b:   55                      push   %ebp                 // 把ebp寄存器的内容压入栈中,也就是保存栈帧寄存器
     804840c:   89 e5                   mov    %esp,%ebp            // 将esp中的内容拷贝到ebp中,也就是将帧指针指向栈指针
     804840e:   83 ec 10                sub    $0x10,%esp           // 调整栈指针,存放局部变量(栈顶增加了4*4字节的空间)
     8048411:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%ebp)      // 局部变量tmp(0)的值存入栈底      
     8048418:   8b 55 08                mov    0x8(%ebp),%edx       // 取出x的值
     804841b:   8b 45 0c                mov    0xc(%ebp),%eax       // 取出y的值
     804841e:   01 d0                   add    %edx,%eax            // x+y的结果存入%eax寄存器中
     8048420:   89 45 fc                mov    %eax,-0x4(%ebp)      // x+y的结果存入局部变量tmp的地址处
     8048423:   8b 45 fc                mov    -0x4(%ebp),%eax      // x+y的结果存入%eax寄存器中
     8048426:   c9                      leave  
     8048427:   c3                      ret    
    
    08048428 <main>:
     8048428:   8d 4c 24 04             lea    0x4(%esp),%ecx
     804842c:   83 e4 f0                and    $0xfffffff0,%esp
     804842f:   ff 71 fc                pushl  -0x4(%ecx)
     8048432:   55                      push   %ebp                 // 把ebp寄存器的内容压入栈中,也就是保存栈帧寄存器
     8048433:   89 e5                   mov    %esp,%ebp            // 将esp中的内容拷贝到ebp中,也就是将帧指针指向栈指针
     8048435:   51                      push   %ecx                 // 保护ecx寄存器的内容
     8048436:   83 ec 14                sub    $0x14,%esp           // 调整栈指针,存放局部变量(栈顶增加了5*4字节的空间)
     8048439:   c7 45 ec 0a 00 00 00    movl   $0xa,-0x14(%ebp)     // 局部变量a(10)的值存入栈底-20
     8048440:   c7 45 f0 14 00 00 00    movl   $0x14,-0x10(%ebp)    // 局部变量b(20)的值存入栈底-16地址处
     8048447:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)      // 局部变量ret(0)的值存入栈底-12地址处
     804844e:   ff 75 f0                pushl  -0x10(%ebp)          // 向函数sum()的参数x传实参a(10),并压栈
     8048451:   ff 75 ec                pushl  -0x14(%ebp)          // 向函数sum()的参数y传实参b(20),并压栈
     8048454:   e8 b2 ff ff ff          call   804840b <sum>        // 调用sum()函数
     8048459:   83 c4 08                add    $0x8,%esp            // 调整栈顶位置(+8),
     804845c:   89 45 f4                mov    %eax,-0xc(%ebp)      // 相加结果(30)存入局部变量ret(0)所在(栈底-12)地址中
     804845f:   83 ec 08                sub    $0x8,%esp            // 调整栈顶位置(-8)
     8048462:   ff 75 f4                pushl  -0xc(%ebp)           // 
     8048465:   68 00 85 04 08          push   $0x8048500
     804846a:   e8 71 fe ff ff          call   80482e0 <printf@plt>
     804846f:   83 c4 10                add    $0x10,%esp
     8048472:   b8 00 00 00 00          mov    $0x0,%eax
     8048477:   8b 4d fc                mov    -0x4(%ebp),%ecx
     804847a:   c9                      leave  
     804847b:   8d 61 fc                lea    -0x4(%ecx),%esp
     804847e:   c3                      ret    
     804847f:   90                      nop
    

    下面我们通过图示的方法,展示函数调用的过程:

    Figure 15-5-3

    这里我们有几个假设条件:

    1. 我们假设这儿的栈实现方式是 满栈,所谓的 满栈就是在压栈的时候,地址先自加4,然后再存储数值。另外一种方式就是 空栈,而空栈就是先存储值,然后再把地址加4。
    2. 本文只研究 mainsum之间的函数栈帧,对于 printf以及 main函数之前和之后的启动和结束代码不作研究;

    相关文章:栈缓存溢出

    展开全文
  • 注意使用的时候的调用过程,以及的函数等等。注释的代码是我乱搞的,也不知道对不对。 正确的姿势,是非注释部分模仿调用过程写的代码。#include #include #include #include #include #include #...

    注意使用栈的时候的栈的调用过程,以及栈的函数等等。注释的代码是我乱搞的,也不知道对不对。

    正确的姿势,是非注释部分模仿栈的调用过程写的代码。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    using namespace std;
    const int MAXN=1000+10;
    int main()
    {
        int n;
        while(cin>>n)
        {
            /*stack<int> s;
            int a[100],b[100];
            for(int i=1;i<=n;i++)
                cin>>a[i];
            int i=1;
            s.push(a[i]);
            i++;
            int k=0;
            while(i<=n)
            {
                int t=s.top();
                while(a[i]<t&&i<=n)
                {
                    s.push(a[i]);
                    i++;
                }
                int j=0;
              //  cout<<s.size()<<endl;
                while(!s.empty())
                {
                     j++;
                     b[k+j]=s.top();
                     s.pop();
                }
                k=k+j;
                if(i<=n)
                s.push(a[i]);
                i++;
            }
            int j=1;
          //  cout<<s.size()<<endl;
            while(!s.empty()) {b[k+j]=s.top();s.pop();j++;}
       //     for(int i=1;i<=n;i++)
         //       cout<<b[i]<<' ';
            int x;
            for(x=1;x<=n;x++)
                if(x!=b[x])
                    break;
            if(x!=n+1)
                cout<<"No"<<endl;
            else
                cout<<"YES"<<endl;*/
            int target[MAXN];
            stack<int> s;
            int A=1,B=1;
            for(int i=1;i<=n;i++)
                cin>>target[i];
            int ok=1;
            while(B<=n)
            {
                if(A==target[B]) {A++;B++;}
                else if(!s.empty()&&s.top()==target[B]) {s.pop();B++;}
                else if(A<=n) s.push(A++);
                else {ok=0;break;}
            }
            cout<<(ok?"Yes":"No")<<endl;
        }
        return 0;
    }
    

    展开全文
  • •称之为“”是因为发生函数调用时,调用函数(caller)的状态被保存在内,被调用函数(callee)的状态被压入调用栈的栈顶 •在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller

    栈的基础知识

    eip寄存器 存放的指针指向程序即将执行到的地址

    esp(32位)/rsp(64位)寄存器 存放函数的栈顶指针

    ebp/rbp寄存器 存放函数的栈底指针

    函数调用栈

    过程

    •函数调用栈是指程序运行时内存一段连续的区域

    •用来保存函数运行时的状态信息,包括函数参数与局部变量等

    •称之为“栈”是因为发生函数调用时,调用函数(caller)的状态被保存在栈内,被调用函数(callee)的状态被压入调用栈的栈顶

    •在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller)的状态

    •函数调用栈在内存中从高地址向低地址生长,所以栈顶对应的内存地址在压栈时变小,退栈时变大

    在这里插入图片描述

    栈帧

    栈帧储存的是一个函数在栈中的信息,一般来说相邻的栈帧的关系是父函数与子函数之间的关系,子函数的栈底指针会保存父函数栈底指针的地址。

    在这里插入图片描述

    函数调用栈的工作方式(32位)

    在这里插入图片描述

    ① 将ebp压入栈中

    ②将ebp指针指向esp指针指向的位置

    ③ 将esp向下增长0x10个字长(4字节)

    ④再向下开辟一段内存,用于存放向函数中传入的3 2 1 值,esp始终指向栈顶,所以向栈中压入数据时,esp会自动的向下移动位置

    ⑤eip指到了调用子函数的地址,所以eip紧接着就跳到了子函数开始的地址,此时esp也在栈中开辟了return adress(callee)空间,用于存放eip指向子函数之前的地址。

    ⑥ 同步骤①,同时还要在栈中开辟空间存放父函数的ebp指针指向的地址

    ⑦ 计算

    ⑧ 子函数的内容执行完毕,eip向下移动准备释放子函数的栈帧空间。

    pop ebp :将栈顶esp指向的地址中的值弹到ebp中。

    在该实例中的意思就是:将父函数的ebp指针的地址弹到ebp寄存器中,使得ebp指向父函数的栈底,为释放子函数的栈帧做铺垫。

    ⑨ ret操作之后子函数执行完毕,继续执行父函数(main),执行完毕以后进行操作->leave->ret

    函数调用栈到此结束!!

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    关于32位和64位程序中函数参数的补充

    x86(32位)程序
    使用栈来传递参数
    使用 eax 存放返回值
    amd64位程序
    前6个参数依次存放于 rdi、rsi、rdx、rcx、r8、r9 寄存器中
    第7个以后的参数存放于栈中

    展开全文
  • 浅析函数调用栈过程

    2019-04-30 13:03:45
    先列出栈调用的基本原则 栈是通过rsp(栈顶指针)、rbp(栈底指针)两个指针来标识的 对于栈上的访问都是通过栈底指针($rbp)的偏移来访问的 函数调用跳转时(callq)在新帧的栈首8Bytes存放上一帧的指令地址($rip...
  • 函数调用为ABI规范的内容,...Arm+Linux平台下函数调用过程的研究 1.C语言代码: int add(int a, int b, int c, int d, int e) { int f = 3; int g = 4; return (a + b + c + d + e + f + g); } ...
  • perf打印调用栈过程

    2018-07-05 23:19:00
    perf_prepare_sample-->perf_callchain-->...上面的调用栈会使用 perf_event_output--> 0xffffffff811837f0 : perf_event_output+0x0/0x80 [kernel]0xffffffff81183a1f : __perf_event_overf...
  • 图解函数调用过程: 1首先是test函数的结构,其中黄色是test函数的,绿色是调用test函数的函数的,比如main函数之类的。 2 test执行到call指令: call 8049262 首先 系统自动压入返回...
  • 的定义 1.它是一种运算受限的...程序中的–函数调用栈 函数调用栈是指程序运行时内存一段连续的区域,用来保存函数运行时的状态信息,包括函数参数与局部变量等 函数调用栈在内存中从高地址向低地址生长,...
  • 函数调用过程 线程执行的基本行为是函数调用,每次函数调用的数据都是通过Java传递的。Java与数据结构上的有类似的含义,它是一块先进后出的数据结构,只支持入栈和出栈两种操作。Java的主要内容是栈帧。...
  • 一种受限制的线性表,底为高地址...esp:即MIPS中的sp,用来存储函数调用栈的栈顶地址,在出栈和压栈时发生变化 C代码 #include <stdio.h> int Add(int x, int y) { int z = 0; z = x + y; return...
  • 区随着函数调用动态变化,每个函数调用时在上占用的空间称为栈帧。用一个示例来说明上保存的内容及动态变化的过程。  下面是一个程序,生成一个对话框显示一条“Hello World!”消息。下面是该程序的C代码:...
  • C函数调用栈过程分析

    2015-12-21 22:59:25
     在此之前,我对C中函数调用过程的变化,仅限于了解有好几种参数的入栈顺序,其中的按照形参逆序入栈是比较常见的,也仅限于了解到这个程度,但到底在一个函数A里面,调用另一个函数B的过程中,函数A的是怎么...
  • 图解函数调用过程: 1首先是test函数的结构,其中黄色是test函数的,绿色是调用test函数的函数的,比如main函数之类的。 2 test执行到call指令: call 8049262 首先 系统自动压入返回...
  • 函数调用过程-函数

    2017-12-19 15:16:00
    在func_A调用func_B的时候,同样先在自己的栈帧中压入函数返回地址,然后为func_B创建新栈帧并压入系统在func_B返回时,func_B的栈帧被弹出系统,func_A栈帧中的返回地址被“露”在栈顶,此时处理器按照这个返回...
  • %rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改 %r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存...
  • : 在32位系统中一个进程可以分到4gb的虚拟...对于函数的调用:父函数调用子函数,当子函数完成后,cpu将返回到父函数的下一行继续执行,这和的先入后出的结构是非常相似的,所以在c语言中使用了的结构来辅助函
  • 小例子一步一步解释“函数调用过程的变化过程” 1 问题描述  在此之前,我对C中函数调用过程的变化,仅限于了解有好几种参数的入栈顺序,其中的按照形参逆序入栈是比较常见的,也仅限于了解到...
  • 大家都知道Spring容器启动时,主要通过调用org.springframework.context.support.AbstractApplicationContext#refresh 方法,但是在调用过程中,有很多的调用链,分析起来很麻烦,出于这个目的,我打算写个小插件,...
  • 函数调用过程中函数详解 2018年08月14日 16:19:51 芹泽 阅读数:69更多 个人分类: 操作系统   当进程被加载到内存时,会被分成很多段 代码段:保存程序文本,指令指针EIP就是指向代码段,可读可执行不...
  • 一、寄存器的使用惯例。 二、调用过程
  • C语言函数栈调用

    2015-08-04 15:12:09
    本节通过代码实例分析函数调用过程中栈帧的布局、形成和消亡。 6.1 栈帧的布局 示例代码如下: //StackReg.c #include //获取函数运行时寄存器%ebp和%esp的值 #define FETCH_SREG(_ebp, _esp) do{\...
  • 差不多每个程序员都知道,函数调用过程,就是层层入栈出栈的过程。 那么这个过程中的详细的细节是什么样子的呢? 阅读了以下几篇文章之后,对整个过程基本理解了: C函数调用过程原理及函数栈帧分析 阅读经典——...
  • 过程调用与运行时

    2020-10-01 11:57:30
    控制转移:过程P调用过程Q,进入过程Q时,程序计数器设置为Q的代码起始地址,在Q执行完成返回时,需要把程序计数器设置为P调用Q位置的下一条指令地址。 参数传递:P必须为Q提供若干个参数,Q可以向Q返回一个值 ...
  • 桢通俗来讲,桢就是函数的调用过程是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。
  • 小例子一步一步解释“函数调用过程的变化过程” 1 问题描述  在此之前,我对C中函数调用过程的变化,仅限于了解有好几种参数的入栈顺序,其中的按照形参逆序入栈是比较常见的,也仅限于了解到...
  • 分析函数调用过程 首先,main函数也是被其他函数调用的,通过调用桢窗口可以看到调用main函数的函数,所谓,...函数调用过程中要开辟一段空间,用于调用过程中临时变量的保存,现场保护。这段空间称之为桢。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,138
精华内容 2,455
关键字:

栈调用过程