開啟Xcode組合偵錯
選中Always Show Disassembly項。
XCode -> Debug -> Debug Workflow -> Always Show Disassembly
在計算機中,雖然資料是儲存在記憶體中,但記憶體中資料的加減計算並不是在記憶體中直接進行的。
而是把記憶體中的資料賦值到暫存器中,然後CPU在暫存器中計算好後把結果再賦值到記憶體中的。
對記憶體中3做加1計算,並把幾個4儲存到藍色記憶體塊中
movq 紅色儲存空間, %rax addq $0x1, $rax movq %rax, 藍色地址空間
組合語言和機器語言是一一對應的。
組合語言通過組合器可以變成機器語言,機器語言通過反組合又可以轉成組合語言。
高階語言通過編譯器可以變成組合語言,組合語言無法通過反編譯轉成高階語言了。
組合語言種類
8086組合(16bit)
x86組合(32bit)
x64組合(64bit)
ARM組合(嵌入式,移動裝置)
對應iOS開發來說,iOS模擬器使用的AT&T組合,iOS真機使用的ARM組合。
OC和Swift偵錯的組合指令是AT&T
它的資料移動操作順序是從左往右,比如movq指令是將左邊暫存器的值移動到右邊的暫存器中。
資料的移動:
movq -0x18(%rbp) , %rax //表示將%rbp-0x18 這個記憶體地址中儲存的值移到 %rax暫存器中
地址的移動:
leaq -0x18(%rbp) , %rax //表示將%rbp-0x18 這個地址移到 %rax暫存器中
call 記憶體地址 // 方法呼叫
jmp 記憶體地址 // if 跳轉
addq $0x1, $rax // 賦值,把左邊的值設定到右邊的暫存器中
mov 與 movq相比多了一個q, 這個q是什麼意思呢?
q代表儲存資料要用多少個位元組,q:64-bits, 8位元組。
指令在記憶體中是順序儲存的,基本上每條指令佔4位元組。
call和jmp指令相似
call是方法呼叫,jmp是if判斷。
call是和ret配合使用的 call 0x00是跳到這個函數地址,等函數執行完,走到ret後會回到call指令的下一句的。
jmp是順序執行,jmp 0x00後一直順序往下執行。
call和jmp跳一個動態的函數地址時,命令是call *的,如:call *%rax。
從暫存器的發展來看是由小到大,比如從x86的32位元組,到x64的64位元組,它們是怎麼相容的呢?
解決方法是共用一個64位元暫存器的記憶體,按照所佔記憶體大小,從低位往高位佔據。比如32位元暫存器只使用64位元全部空間的一半,佔據暫存器的低地址區。
%rip, %rdx, 以r開頭的是64位元8位元組暫存器
%esi, %idx, 以e開頭的是32位元4位元組暫存器
其他的
ax ,bx, cx 佔2位元組
ah, al 佔1位元組
lldb組合偵錯指令
記憶體/暫存器讀寫
讀取暫存器中的值
register read/格式
register read/x
修改暫存器中的值
register write 暫存器名稱 數值
register write rax 0
讀取記憶體中的值
x/數值-格式-位元組大小 記憶體地址
x/3xw 0x000010
修改記憶體中的值
memory write 記憶體地址 數值
memory write 0x000010 10
組合斷點偵錯
thread step-inst-over, nexti, ni //單步執行,把子函數當做一個整體,一步執行
thread step-inst, stepi, si //單步執行,遇到子函數進入子函數
記憶體地址計算
當組合呼叫,程式走到斷點的位置時,要驗證movq $0xa, 0x459d(%rip)這塊組合執行的效果時
會手動計算記憶體地址 = %rip + 0x459d
注意,此時從暫存器%rip拿到的值是錯的,因為CPU的指令暫存器是儲存的下一條指令要執行的地址
而當前斷點斷住了,相當於在CPU準備執行這個命令時會有一次執行下調指令的計算沒有做,如果直接讀取,那麼讀到的是還是CPU上一次的更新執行當前指令地址的值,正確的執行上下文時,應該是下一條指令的地址值。
%rip: 指令暫存器
iOS傳參優先使用暫存器傳參,暫存器不夠了用棧傳參。
記憶體地址格式規律
0x4bdc(%rip),一般是全域性變數,全域性區(資料段)
-0x78(%rbp), 一般是區域性變數,棧空間
0x10(%rax), 一般是堆空間
常用暫存器
rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp
r8,r9,r10,r11,r12,r13,r14,r15
rax 常用於函數返回值
rcx, rdx, rdi, rsi, r8, r9常用於存放函數引數。
rbp, rsp用於棧操作
rip作為指令指標(存放的是下一條執行指令的地址, 一旦CPU讀取一條指令,rip自動指向下一條指令)