前言
最近準(zhǔn)備學(xué)習(xí)匯編,然后在B站上看到叫iOS小賢的作者發(fā)的視頻挺不錯,打算跟著學(xué)揩魂,文章是看視頻的筆記,最后有原視頻鏈接炮温,想看視頻的可以看看通過鏈接查看視頻火脉。
棧
- 棧:是一種具有特殊的訪問方式的存儲空間(后進(jìn)先出, Last In Out Firt柒啤,LIFO)
Stack 是由內(nèi)存區(qū)域的結(jié)束地址開始倦挂,從高位(地址)向低位(地址)分配。比如担巩,內(nèi)存區(qū)域的結(jié)束地址是0x8000方援,第一幀假定是16字節(jié),那么下一次分配的地址就會從0x7FF0開始涛癌;第二幀假定需要64字節(jié)犯戏,那么地址就會移動到0x7FB0。
注:用戶主動請求而劃分出來的內(nèi)存區(qū)域拳话,叫做 Heap(堆)先匪。它由起始地址開始,從低位(地址)向高位(地址)增長弃衍。Heap 的一個重要特點就是不會自動消失呀非,必須手動釋放,或者由垃圾回收機(jī)制來回收。所謂的堆棧溢出是指堆棧開辟的空間碰到了一起岸裙,重疊猖败,說明空間不夠了。
SP和FP寄存器
- sp寄存器在任意時刻會保存我們棧頂?shù)牡刂?
- fp寄存器也稱為x29寄存器屬于通用寄存器,但是在某些時刻我們利用它保存棧底的地址!()
注意:ARM64開始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
ARM64里面 對棧的操作是16字節(jié)對齊的!!
注:以前push和pop操作的時候需要對寄存器做保護(hù)降允,也就是sp恩闻。做壓棧的操作sp會挪動,之后需要恢復(fù)的時候sp是需要保護(hù)的拟糕,通過fp保護(hù)∨信唬現(xiàn)在push和pop取消了fp就顯得比較雞肋,但是要兼容32位送滞,這個寄存器還保留著侠草。
關(guān)于內(nèi)存讀寫指令
注意:讀/寫 數(shù)據(jù)是都是往高地址讀/寫
str(store register)指令
將數(shù)據(jù)從寄存器中讀出來,存到內(nèi)存中。
ldr(load register)指令
將數(shù)據(jù)從內(nèi)存中讀出來,存到寄存器中
此ldr 和 str 的變種ldp(pair) 和 stp(pair) 還可以操作2個寄存器犁嗅。
堆棧操作練習(xí)
使用32個字節(jié)空間作為這段程序的棻咛椋空間,然后利用棧將x0和x1的值進(jìn)行交換。
sub sp, sp, #0x20 ;拉伸椆游ⅲ空間32個字節(jié)
stp x0, x1, [sp, #0x10] ;sp往上加16個字節(jié),存放x0 和 x1
ldp x1, x0, [sp, #0x10] ;將sp偏移16個字節(jié)的值取出來,放入x1 和 x0
注:sub是減功蜓,sub sp, sp, #0x20
是將ap向底地址挪動32個字節(jié),然后賦值給sp宠蚂。str是將寄存器里面的值放到內(nèi)存中式撼,但是str只能操作一個寄存器,stp可以操作兩個求厕,stp x0, x1, [sp, #0x10]
是將x0和x1放在[sp, #0x10]
著隆,[sp, #0x10]
是一塊內(nèi)存區(qū)域,左邊操作數(shù)加上右邊操作數(shù)呀癣,[sp, #-0x10]
就是左邊操作數(shù)減去右邊操作數(shù)美浦。
我們來寫一下
然后A()出打斷點,并進(jìn)入A方法项栏。
我們看到在執(zhí)行完
sub sp, sp, #0x20
后sp是0x000000016d57b8e0
浦辨,然后查看一下我們來看一下內(nèi)存地址,輸入0x000000016d57b8e0
沼沈,看到內(nèi)存開辟了16個字節(jié)的空間流酬,當(dāng)前sp是在6129432800處,前面講到列另,寫內(nèi)存是往高地址寫康吵,所以stp x0, x1, [sp, #0x10]
是往高地址寫。
現(xiàn)在我們往x0和x1中寫入0xffffffff访递,再ni。
register write x0 0xffffffff
register write x1 0xffffffff
因為stp x0, x1, [sp, #0x10]
所以是從sp加16個字節(jié)出開始存數(shù)據(jù)同辣。
注: add sp, sp, #0x20
是為了棧平衡拷姿,如果不這么做惭载,棧會一直往低地址走,最終內(nèi)存不夠用响巢,但是當(dāng)函數(shù)調(diào)用完局部變量是不需要了描滔,所以要回收棧空間踪古。