java棧幀
① 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>
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>
<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>
<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>
<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>
反匯編之後的代碼;
[html]view plain
2)保存函數的參數
分析代碼:
[html]view plain
註:C中,若函數的參數小於等於4個,則用通用寄存器保存其參數值,多於4個的參數保存在棧中
3)保存寄存器的值
分析代碼:
[html]view plain
反匯編之後的代碼;
[html]view plain
初始化棧:即對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