当前位置:首页 » 编程语言 » java栈帧

java栈帧

发布时间: 2023-01-20 10:50:34

java的类加载后什么时候会被释放

首先,"java的类在第一次需要创建类的实例(对象)时被加载"这个说的不对x0dx0ax0dx0ajava中类被使用就就会时就会被加载到内存(比如反射等)x0dx0a然后回答你的问题。x0dx0ax0dx0a首先要介绍下相关知识(基础知识纯属拷贝):x0dx0ax0dx0a首先来了解一下jvm(java虚拟机)中的几个比较重要的内存区域x0dx0ax0dx0a方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。x0dx0a常量池:常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。x0dx0a堆区:用于存放类的对象实例。x0dx0a栈区:也叫java虚拟机栈,是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。x0dx0a 除了以上四个内存区域之外,jvm中的运行时内存区域还包括本地方法栈和程序计数器,这两个区域与java类的生命周期关系不是很大,在这里就不说了,感兴趣可以自己网络一下。x0dx0ax0dx0a其实类在JVM里面有以下几个阶段:x0dx0ax0dx0a加载 -- 连接 -- 初始化 -- 使用 -- 卸载 x0dx0ax0dx0a主要给你说明卸载:x0dx0a在类使用完之后可能会被卸载,可能性如下:x0dx0a如果有下面的情况,类就会被卸载:x0dx0a该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。x0dx0a加载该类的ClassLoader已经被回收。x0dx0a该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。x0dx0a 如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

② Java:栈帧的个数是不是与方法数相同呢也就是每个方法在执行时都有自己唯一的栈帧

不同线程有不同虚拟栈,那是私有的,如果并发操作不会产生竞态,故不会引起并发问题。
如局部变量分布在虚拟机栈,线程安全。但全局变量分布在方法区,是共享的,故会引发并发问题。
java内存模型,堆和方法区是共享的, 本地方法栈、虚拟机栈、程序计数器是私有的

③ java中,静态方法被调用是,存储在内存的哪个区域是栈还是放大区还是两者都有

在JDK8之前,静态成员(静态变量和静态方法)都是存储在方法区(永久代)中的静态区中(这里指类被加载后,静态成员的存储位置)。但在JDK8之后,永久代被移除了,取而代之的是元空间(metaspace)。但元空间中存储的主要是.class文件的元数据信息,静态成员的存储位置由方法区转到了堆内存(heap)中。
不过,不管是JDK8,还是更早的版本中,静态方法的执行(不仅仅是静态方法,还有普通的成员方法)都是在栈内存(stack)中进行的。每个线程都会在栈内存中开辟一个栈,在调用方法时,对应的方法都会在执行这个方法的线程的栈中创建一个“栈帧”,栈帧中保存了局部变量表(基本数据类型和对象引用)、操作数栈、动态连接和返回地址等信息。等到方法执行完毕,栈帧被销毁,对应的内存也将被释放。

我的世界fill指令出错java版

[WARNING] 本篇适用于Minecraft服务端/客户端报错的诊断分析,其他游戏除外,比如网易

[WARNING] 本篇适用于Minecraft服务端/客户端报错的诊断分析,其他游戏除外,比如网易

[WARNING] 本篇适用于Minecraft服务端/客户端报错的诊断分析,其他游戏除外,比如网易

我所说的报错,指的是一款名为《Minecraft》的游戏中的报错。并不是《我的世界》的报错

在大家游玩Minecraft时,有时需要装一些Forge模组以此来提高可玩度,但自己配置模组包的时候,总会造成游戏崩溃,并且大多数人还看不懂崩溃报告更有甚者连崩溃报告输出目录都不知道在哪,于是本篇教程应运而生。

一些俏皮话

Minecraft这个游戏,各种BUG和解决方案如果写成一堆不重复的书,摞起来的厚度可以比姚明还高。

所以这个游戏不是一般的神奇,尤其是当你在看崩溃报告的时,你更会体验到这一点。

你不加模组,MC也会崩溃,加了还是崩溃。这是一个比较罕见的情况。

大多数情况是你一股脑加了一堆模组,然后突然蹦了,就不知道怎么办了。

幸运的是,这时候,你有60%的概率可以找到问题所在并解决这个问题。

寻找崩溃日志

首先,你得知道你的客户端/服务端目录

客户端的CrashReport文件夹目录:(.minecraft\crash-reports)

如果你启用了版本隔离,那就在(.minecraft\versions\xxxx\crash-reports)

服务端的CrashReport在你的服务端根目录下。

这个条件的前提是你的服务端是人类已知的服务端,而不是外星人制造的服务端。

打开崩溃日志

接下来我们对报错的分析,均以一个Minecraft 1.12.2 Forge服务端为例

嗯,我们可以看到,crashreport目录下的所有文件都是以

crash-日期_具体时间-server.txt命名的

如果是客户端的崩溃报告日志,后面的server则是client。

然后我们找到一个最新的日志打开并分析。

告诉你怎么瞬间找到最新崩溃日志,

直接点击这个按钮就完事了。然后会按照报告的生成时间进行排列。

重要的事说三遍

接下来我们对报错的分析,均以一个Minecraft 1.12.2 Forge服务端为例

接下来我们对报错的分析,均以一个Minecraft 1.12.2 Forge服务端为例

接下来我们对报错的分析,均以一个Minecraft 1.12.2 Forge服务端为例

下载文本编辑器

首先你需要一个文本编辑器来查看崩溃报告,

这里我推荐微软官方的Visaul Code: 点我下载.

然后我们就可以愉快地打开报告进行查看了。

开始分析

好了,我们说了这么多废话,是时候开始正式的分析了。

我估计前面的事大多数人已经做完了,就等着我讲这个。

废话不多说,开始。

打开后我们首先看到的是这个

其中,WARNING coremods are present:xxxxx 是废话,你根本不用管。
产生这种警告是因为有的作者动了Minecraft底层的代码,然后Forge为了方便,给你整出来了。

在99.9999999%的情况下,coremods在理论上不会造成崩溃。所以你可以忽略这些。

再往下看。

我们先引出几个重要概念,当然你不用理解。
你会发现这些报错里都会有一大堆的文字:

at net.xxxxx

at org.xxxxxxxx

at com.xxxxxx

at java.lang.xxxx

这些有专门的术语,叫做栈帧(stacktrace)。

CPU寄存器的空间是极其有限的,因此方法的调用需要在栈上开辟空间,每调用一个方法就会生成一个栈帧,因此崩溃报告里的一堆at at

at所代表的一系列栈帧,某种意义上是一条调用链,最后被调用的方法(也就是爆出异常的方法)会被崩溃报告放在最上面

我们可以看见,顶上有

这3行东西,

第一行是废话,你可以不用管。

第二行这个报告中最后一个栈帧抛出异常的时间。

第三行是这个报错的描述,也就是人类可读的大白话形式。

从这开始,下面的句子都不是人类可读形式,当然。相比原版的报错来说,Forge的报错非常非常人性化了。

我们可以从第三行看到,这个崩溃报告的描述是 Ticking player。

player代表球员 玩家,也就是说这个报错跟玩家有关系。

Tciking指的是刻,这个以后再说。

然后我们再来看下面的报错

这个报错片段中。
第一行是错误类型

我们可以看到,这个报错的错误类型是

java.lang.IndexOutOfBoundsException

如果你开过Minecraft群组服务器,或者学过java。你可以知道

这个叫做数组下标越界异常,是一个在Minecraft中非常常见的异常。

我们不用去管这个具体是什么,直接往下看。

下面那些一大堆栈帧的排列,并非没有顺序。

这些栈帧的排列方式,是由它们抛出异常的顺序决定的。

听不懂?我们看图

红色箭头指的栈帧,是第一个抛出异常的栈帧。
然后黄色箭头的栈帧,是最后一个抛出异常的栈帧。

现在你懂了栈帧的排列顺序了吧。

最前面的栈帧就是最后一个抛出错误的位置,也就是说大多数情况我们是从这里下手。

或者从第一个栈帧的后面几个栈帧下手。

好,我们继续看。

现在我们遇到的是指数组下标越界异常。

例如:一个ArrayList数组中没有元素,而你想获取第一个元素,运行是就会报此类型的错误。

听不懂?我们看报错!

看看,最后栈帧抛出的异常,就是ArrayList在获取元素的时候没找到。

当然你不用在意这个,继续往下看。

这里已经出现了产生这个崩溃的模组名字。
这个模组叫做:slashblade,也就是大家经常玩的拔刀剑。

然后你发现,这些栈帧的形式都是

at xxx.xxxxxxx.xxxxxx.xxxxxxxx.xxxxxxx.xxxxxx(xxxx.java:xxxx)

如果你以压缩包形式打开拔刀剑模组JAR文件,

你会发现一件事。

那就是这些栈帧其实就是这个JAR压缩包的内部目录结构!!!!!

就比如这条栈帧

at mods.flammpfeil.slashblade.item.ItemSlashBlade$ComboSequence.get(ItemSlashBlade.java:310)

我们可以把所有的" . “去掉,改成” / 或者 \ "

这样就是一个文件目录了!!

at mods.flammpfeil.slashblade.item.ItemSlashBlade$ComboSequence.get(ItemSlashBlade.java:310)

相当于

at mods\flammpfeil\slashblade\item\itemSlashBlade

而这段蓝色的,ComboSequence.get,指的是这个栈帧中抛出异常的方法。并不是文件目录。
括号里的ItemSlashBlade.java:310指的是,

这个异常发生在

ItemSlashBlade.java这个文件夹中的第310行。

是不是突然明白一大堆东西!!!!!!!!!

下面的图就是我用压缩包形式打开拔刀剑模组文件后,

把栈帧转换成目录,就找到了抛出异常的文件路径。

深度分析

好了,那么我们接下来进行硬核(Hardcore)分析吧

上面我们已经找到了这个崩溃中有拔刀剑的信息

那么我们就进一步分析。

我们知道,拔刀剑有几个栈帧抛出了异常,那么我们以最后一个抛出异常的栈帧进行分析。

amods.flammpfeil.slashblade.item.ItemSlashBlade$ComboSequence.get

从这段信息中我们得知,这个抛出异常的方法在ComboSequence.Get中

ComboSequence翻译过来就是组合技,然后我们进一步分析

既然这个崩溃出在了拔刀剑的组合技上,那也就是说。

我的服务器崩溃是因为,有某个人用了拔刀的组合技,然后不知道触发了什么BUG。服务器就因此崩溃了。

很好,如果你能分析到这一步,那就快接近真相了!

上 代 码

我们首先登陆Github(世界上最大的代码托管站)

然后找到拔刀剑的开源代码仓库,并依次进入目录

src/main/java/mods/flammpfeil/slashblade/item/ItemSlashBlade.java

然后这个就是抛出异常的原代码了。

然后搜索方法 ComboSequence.get

//报错产生的位置

public static ComboSequence getComboSequence(NBTTagCompound tag){

return ComboSequence.get(tag.getInt(comboSeqStr));

}

很好,你可能看见一个熟悉的词汇,叫做NBT

我们引用一段网络上的话

二进制命名标签(Name Binary Tag),NBT格式为Minecraft中用于向文件中存储数据的一种存储格式。NBT格式以树形结构并配以许多标签的形式存储数据

既然如此,我们就可以知道

这个报错的产生和NBT标签有关系,然后我们只需要看见tag这个词即可。

这就代表,这个异常的产生是因为在获取组合技的NBT数据时产生异常,在结合最后一个抛出的异常

也就是数组下标越界异常

我们就可以推导出这个异常的产生了。

一个玩家在使用拔刀的组合技时,然后这个组合技因为某种原因无法使用,也就是ArrayList数组元素为空,导致抛出数组下标越界异常,引发Minecraft服务器保护机制然后自动关服。并产生这个报错。

好了,我们继续看下面的栈帧。

对于下面的栈帧来说,上面的栈帧全是主要原因。也就是说下面的栈帧都是废话

不过我还是贴出来让你了解一下。

很好,接下来我们看红圈内的栈帧。
其中所有 net.minecraftforge.fml.xxxx的栈帧,基本上没什么有价值的信息。

我们继续看下面 net.minecraft.xxxx的栈帧,我们可以看到关键词汇那就是entity。

得出结论

Entity就是实体的意思,也就是说这个东西出现在玩家使用组合技与实体进行交互时才发生的数组下标跃境异常

我们继续看

这2段代表了有关玩家的信息,意义不大。

我们在这些栈帧中可以看到有network和server单词。
这代表这些栈帧与网络和服务端关西了。

这段也是意义不大,而且与拔刀剑产生的报错无关,我们继续看。

这段才是好戏,我们可以看到一个词组叫playerLoggedOut,这个代表玩家登出服务器。

也就是玩家掉线

然后我们结合这些堆栈抛出异常的顺序。

我们就可以得知一个大概顺序。

玩家使用组合技后,首先从掉线

然后服务端发现异常

然后服务端整理崩溃后就关闭服务器了。

很好,我们对错误的分析已经结束了。

接下来我们继续往下看!

完成看崩溃报告的栈帧并得出结论~

修复报错

这是下面的内容。
我们可以看到大大的Head (头部)字样

然后Thread(线程): Server thread(主线程)

我们可以得到一个信息

那就是说,这些栈帧抛出错误是在服务器主线程上抛出的,所以才会导致服务器自我保护机制开启并关闭服务器。

我们继续往下看。

我们可以看见大大的 Player being ticked
这段代表有关出错实体的名字。

然后既然出现了Player,代表这个实体是玩家。

也就代表,这个是出错的实体是玩家。因为那个错误拔刀剑在玩家手上。所以出错实体是玩家。

然后

Entity Type是实体类型,Entity ID是实体的ID,Name就不用解释了,是实体名。

因为这个实体是玩家,所以实体名就是玩家名。

⑤ 在计算机中运行Java程序时,堆内存中存放着临时数据。+(+)

不完全对,不只是堆内存,栈中也同样保存着临时数据
其中每个线程的栈中存储的内容都是独立的,而堆内存是共享的,所以在多线程编程时由于堆内存共享,会导致一些多线程安全问题,如:多线程的i++问题

栈中包含栈帧,每一个方法都是一个栈帧,当一个线程中有多个方法的时候,会进行压栈和弹栈的操作,如:一个线程先访问A方法,然后访问B方法,这时候就会先把栈帧A压栈,然后栈帧B再压栈,而弹栈的时候是先入后出的,也就是B先弹出,然后是A。
每一个栈帧又分别包含:局部变量表,操作数栈,动态链接和方法返回地址
局部变量表:存储方法中定义的各个局部变量
操作数栈:存储方法中的一些临时的计算结果
动态链接:把符号引用转为直接引用,因为在程序启动的过程中,其实我们并没有真的引用到Java的工具方法,而是使用一个符号做标记,当真正使用的时候再将标记直接指向具体方法
方法返回地址:记录方法执行结束后的指针,也就是我当前方法执行结束后需要干什么

⑥ jvm栈帧包含哪些内容

当线程执行到某个方法时就会往方线程栈中压入一个帧,称为栈帧,栈帧中包含了方法的局部变量表、操作数栈、返回地址、动态连接等信息
局部变量表:
顾名思义就是用来存储java方法中的局部变量的,在编译期间就会分配方法局部变量表的最大容量,局部变量表以变量槽为单位,每个变量槽可以存储32位及32位以下的变量,具体大小根据变量实际占用内存而定,java的基本类型中除了long和double外其他类型都是32位以下,所以每个变量占用一个变量槽即可,而对于long和double类的变量,会占用两个变量槽,除了基本类型当然还有引用类型,引用类型变量长度JVM并没有明确定义。JVM通过索引的方式来访问变量表中的变量,索引从0开始。变量槽是可以重复使用的,当变量槽所存储的变量已经不在其作用域后,该变量槽就可以被其他变量占用
操作数栈:
用于在方法运行时可以存放以及获取操作数,其所需要的最大栈深度也是在编译期间定下的,在方法刚开始运行时,操作数栈是空的,在方法执行过程中会有各种操作指令往操作数栈中压入和获取内容,也就是出栈/入栈操作,比如一个加法指令对两个数据进行相加,运行到这里前会先将两个数据压入栈中,然后将这两个操作数取出相加;在实际情况中,方法的操作数栈之间并不完全独立,往往会公用部分空间,这样在方法调用时就不需要进行参数复制了
动态连接:
前面说了常量池中会存储方法的符号引用,而每个栈帧中都会存储一个引用,用于指向常量池中该方法对应的符号引用,字节码指令中方法的调用就以方法对应的符号引用为参数来进行,在类加载阶段的解析步骤中,部分符号引用会被解析为直接引用,称为静态解析,在方法的运行过程中,另一部分符号引用会被实时的解析为直接引用,称为动态连接。
被静态解析的条件:方法在运行前就有一个可确定的调用版本,其实也就是编译期就刻意确定改方法有没有可能通过继承或者其他方式被重写,在java中静态方法(与类型直接关联),私有方法(外部不可访问),构造方法,父类方法,final方法,这五种方法的符号引用可以被静态解析都不可能被重写,可以在运行前确定唯一的调用版本,满足被静态解析的条件,称为非虚方法。
方法返回地址:
方法的运行过程中,可能会正常退出,也可能会异常退出,不论是哪种退出方式,在退出后都会要保证其上层调用者可以知道方法退出的位置,以便于程序继续执行,方法的返回地址就是用于确定退出位置的。

⑦ 栈帧java中用什么表示

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素。栈帧存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息。第一个方法从调用开始到执行完成,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
每一个栈帧都包括了局部变量表,操作数栈,动态连接,方法返回地址和一些额外的附加信息。在编译代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈 都已经完全确定了,并且写入到了方法表的Code属性中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体虚拟机的实现。

⑧ "栈"和"栈帧"这两个概念到底如何区分

1、栈:FILO先进后出的数据结构

栈底是第一个进栈的数据的位置(压箱底)

栈顶是最后一个进栈的数据位置

2、根据SP指针指向的位置,栈可分为满栈和空栈

满栈:当sp指针总是指向最后压入堆栈的数据(ARM采用满栈)


栈的作用:

1)保存局部变量

分析代码:

[html]view plain

  • #include<stdio.h>

  • intmain()

  • {

  • inta;

  • a++;

  • returna;

  • }</span>


  • 反汇编之后的代码;

    [html]view plain

  • stack:fileformatelf32-littlearm

  • Disassemblyofsection.text:

  • 00000000<main>:

  • #include<stdio.h>

  • intmain()

  • {

  • 0:e52db004push{fp};(strfp,[sp,#-4]!)@将栈帧底部指针FP压入栈中;创建属于main函数的栈帧。

  • 4:e28db000addfp,sp,#0;0x0@fp指针为函数栈帧的底部,

  • 8:e24dd00csubsp,sp,#12;0xc@sp指针为栈帧的顶部,同时为栈的栈顶。

  • inta;

  • a++;

  • c:e51b3008ldrr3,[fp,#-8]@由此三句可知变量a在栈帧中执行了加法操作,及栈帧具有保存局部变量的作用

  • 10:e2833001addr3,r3,#1;0x1

  • 14:e50b3008strr3,[fp,#-8]

  • returna;

  • 18:e51b3008ldrr3,[fp,#-8]

  • }

  • </span>



  • 2)保存函数的参数

    分析代码:

    [html]view plain

  • <spanstyle="font-size:18px;">#include<stdio.h>

  • voidfunc1(inta,intb,intc,intd,inte,intf)

  • {

  • intk;

  • k=e+f;

  • }

  • intmain()

  • {

  • func1(1,2,3,4,5,6);

  • return0;

  • }

  • 反汇编之后的代码;

  • voidfunc1(inta,intb,intc,intd,inte,intf)@多于4个参数

  • {

  • 0:e52db004push{fp};(strfp,[sp,#-4]!)@保存main函数的栈帧底部指针FP

  • 4:e28db000addfp,sp,#0;0x0

  • 8:e24dd01csubsp,sp,#28;0x1c@由栈帧顶部指针SP创建一片栈帧保存子函数的前四个参数

  • c:e50b0010strr0,[fp,#-16]@a

  • 10:e50b1014strr1,[fp,#-20]@b

  • 14:e50b2018strr2,[fp,#-24]@c

  • 18:e50b301cstrr3,[fp,#-28]@d

  • intk;

  • k=e+f;

  • 1c:e59b3004ldrr3,[fp,#4]@在子函数的栈帧中实现第五个参数与第六个参数的运算

  • 20:e59b2008ldrr2,[fp,#8]@由ldrr2,[fp,#8]知参数保存在main函数的栈帧中,并运算

  • 24:e0833002addr3,r3,r2@以子函数的栈帧底部指针(fp)做参考坐标实现对参数的查找

  • 28:e50b3008strr3,[fp,#-8]

  • }

  • 2c:e28bd000addsp,fp,#0;0x0

  • 30:e8bd0800pop{fp}

  • 34:e12fff1ebxlr

  • 00000038<main>:

  • intmain()

  • {

  • 38:e92d4800push{fp,lr}@由于调用子函数,先保存main函数的栈帧底部指针FP和返回地址LR(当前PC指针的下一地址)

  • 3c:e28db004addfp,sp,#4;0x4@可知先压入FP,后压入lr.把此时子函数(被调用者)的栈帧底部指针FP指向保存在子函数栈帧的main函数(调用者)的栈帧底部指针FP

  • 40:e24dd008subsp,sp,#8;0x8@创建栈

  • func1(1,2,3,4,5,6);

  • 44:e3a03005movr3,#5;0x5

  • 48:e58d3000strr3,[sp]

  • 4c:e3a03006movr3,#6;0x6

  • 50:e58d3004strr3,[sp,#4]

  • 54:e3a00001movr0,#1;0x1@用通用寄存器保存前四个参数的值

  • 58:e3a01002movr1,#2;0x2

  • 5c:e3a02003movr2,#3;0x3

  • 60:e3a03004movr3,#4;0x4

  • 64:ebfffffebl0<func1>

  • return0;

  • 68:e3a03000movr3,#0;0x0

  • }

  • 6c:e1a00003movr0,r3

  • 70:e24bd004subsp,fp,#4;0x4

  • 74:e8bd4800pop{fp,lr}

  • 78:e12fff1ebxlr</span>


  • 注:C中,若函数的参数小于等于4个,则用通用寄存器保存其参数值,多于4个的参数保存在栈中

    3)保存寄存器的值

    分析代码:

    [html]view plain

  • <spanstyle="font-size:18px;">include<stdio.h>

  • voidfunc2(inta,intb)

  • {

  • intk;

  • k=a+b;

  • }

  • voidfunc1(inta,intb)

  • {

  • intc;

  • func2(3,4);

  • c=a+b;

  • }

  • intmain()

  • {

  • func1(1,2);

  • return0;

  • }</span>


  • 反汇编之后的代码;

    [html]view plain

  • <spanstyle="font-size:18px;">voidfunc2(inta,intb)

  • {

  • 0:e52db004push{fp};(strfp,[sp,#-4]!)

  • 4:e28db000addfp,sp,#0;0x0

  • 8:e24dd014subsp,sp,#20;0x14

  • c:e50b0010strr0,[fp,#-16]@保存寄存器的值

  • 10:e50b1014strr1,[fp,#-20]

  • intk;

  • k=a+b;

  • 14:e51b3010ldrr3,[fp,#-16]

  • 18:e51b2014ldrr2,[fp,#-20]

  • 1c:e0833002addr3,r3,r2

  • 20:e50b3008strr3,[fp,#-8]

  • }

  • 24:e28bd000addsp,fp,#0;0x0

  • 28:e8bd0800pop{fp}

  • 2c:e12fff1ebxlr

  • 00000030<func1>:

  • voidfunc1(inta,intb)

  • {

  • 30:e92d4800push{fp,lr}

  • 34:e28db004addfp,sp,#4;0x4

  • 38:e24dd010subsp,sp,#16;0x10

  • 3c:e50b0010strr0,[fp,#-16]@代码44行调用func2函数后,又使用r0 1保存参数,所以此时将r0 1寄存器的

  • 40:e50b1014strr1,[fp,#-20]@值放入栈中

  • intc;

  • func2(3,4);

  • 44:e3a00003movr0,#3;0x3

  • 48:e3a01004movr1,#4;0x4

  • 4c:ebfffffebl0<func2>

  • c=a+b;

  • 50:e51b3010ldrr3,[fp,#-16]

  • 54:e51b2014ldrr2,[fp,#-20]

  • 58:e0833002addr3,r3,r2

  • 5c:e50b3008strr3,[fp,#-8]

  • }

  • 60:e24bd004subsp,fp,#4;0x4

  • 64:e8bd4800pop{fp,lr}

  • 68:e12fff1ebxlr

  • 0000006c<main>:

  • intmain()

  • {

  • 6c:e92d4800push{fp,lr}

  • 70:e28db004addfp,sp,#4;0x4

  • func1(1,2);

  • 74:e3a00001movr0,#1;0x1

  • 78:e3a01002movr1,#2;0x2

  • 7c:ebfffffebl30<func1>

  • return0;

  • 80:e3a03000movr3,#0;0x0

  • }

  • 84:e1a00003movr0,r3

  • 88:e24bd004subsp,fp,#4;0x4

  • 8c:e8bd4800pop{fp,lr}

  • 90:e12fff1ebxlr</span>


  • 初始化栈:即对SP指针赋予一个内存地址(统一标准:2440、6410、210)

    在内存的64MB位置即ldr sp, =0x34000000(2440)

    ldr sp, =0x54000000(6410)

    ldr sp, =0x24000000(210)

    由上可知ARM采用满栈(指向刚入栈的数据)、降栈(由高地址向低地址入栈)

    问题:因为ARM不同工作模式有不同的栈,定义栈的技巧是什么,避免定义相同的地址使用不同栈?

    转自:http://blog.csdn.net/u011467781/article/details/39559737

热点内容
安卓系统下载铃声在哪个文件夹 发布:2025-07-18 12:52:11 浏览:271
qt程序一样但是无法编译 发布:2025-07-18 12:32:45 浏览:36
服务器搭建主机配置 发布:2025-07-18 12:12:43 浏览:126
ftp命令批量下载文件 发布:2025-07-18 11:58:45 浏览:744
nba2k17文件夹 发布:2025-07-18 11:48:53 浏览:871
朔源码是什么 发布:2025-07-18 11:44:33 浏览:775
迷你世界解压剧场 发布:2025-07-18 11:43:48 浏览:155
linux安装opencv 发布:2025-07-18 11:42:10 浏览:447
编程游戏的软件有哪些 发布:2025-07-18 11:41:34 浏览:957
c程序设计语言电子书 发布:2025-07-18 11:35:58 浏览:643