1.cmp(Compare)比較指令
???CMP 把一個寄存器的內(nèi)容和另一個寄存器的內(nèi)容或立即數(shù)進(jìn)行比較兔院。但不存儲結(jié)果孵稽,只是正確的更改標(biāo)志菩鲜。
???一般CMP做完判斷后會進(jìn)行跳轉(zhuǎn)接校,后面通常會跟上B指令!
- BL 標(biāo)號:跳轉(zhuǎn)到標(biāo)號處執(zhí)行
- B.LT 標(biāo)號:比價結(jié)果是小于(less than)诽凌,執(zhí)行標(biāo)號侣诵,否則不跳轉(zhuǎn)
- B.LE 標(biāo)號:比較結(jié)果是小于等于(less than or qeual to)杜顺,執(zhí)行標(biāo)號躬络,否則不跳轉(zhuǎn)
- B.GT 標(biāo)號:比較結(jié)果是大于(greater than)越锈,執(zhí)行標(biāo)號,否則不跳轉(zhuǎn)
- B.GE 標(biāo)號:比較結(jié)果是大于等于(greater than or equal to)稀拐,執(zhí)行標(biāo)號铲咨,否則不跳轉(zhuǎn)
- B.EQ 標(biāo)號:比較結(jié)果是等于(equal to)纤勒,執(zhí)行標(biāo)號摇天,否則不跳轉(zhuǎn)
- B.NE 標(biāo)號:比較結(jié)果是不等于(not equal to)泉坐,執(zhí)行標(biāo)號腕让,否則不跳轉(zhuǎn)
- B.LS 標(biāo)號:比較結(jié)果是無符號小于等于纯丸,執(zhí)行標(biāo)號觉鼻,否則不跳轉(zhuǎn)
- B.LO 標(biāo)號:比較結(jié)果是無符號小于,執(zhí)行標(biāo)號喘帚,否則不跳轉(zhuǎn)
- B.HI 標(biāo)號:比較結(jié)果是無符號大于吹由,執(zhí)行標(biāo)號粗合,否則不跳轉(zhuǎn)
- B.HS 標(biāo)號:比較結(jié)果是無符號大于等于隙疚,執(zhí)行標(biāo)號供屉,否則不跳轉(zhuǎn)
2.Switch
1伶丐、假設(shè)switch語句的分支比較少的時候(例如3哗魂,少于4的時候沒有意義)沒有必要使用此結(jié)構(gòu)朽色,相當(dāng)于if纵搁。
2腾誉、各個分支常量的差值較大的時候利职,編譯器會在效率還是內(nèi)存進(jìn)行取舍猪贪,這個時候編譯器還是會編譯成類似于if,else的結(jié)構(gòu)桶癣。
3娘锁、在分支比較多的時候:在編譯的時候會生成一個表(跳轉(zhuǎn)表每個地址四個字節(jié))间雀。
I.當(dāng)switch中的case大于三個時惹挟,此時從將不會產(chǎn)生挨個cmp的現(xiàn)象责蝠,會將比較結(jié)果存入表中
0x102f7e110 <+28>: ubfx x9, x9, #0, #32
將x9寄存器的高32位清零齿拂,低32位保留署海,為1
cmp x9, #0x4
將x9寄存器中的值和4進(jìn)行比較
b.hi 0x1008e6178
無符號大于跳0x1008e6178
0x1008e6120 <+44>: adrp x8, 0
0x1008e6124 <+48>: add x8, x8, #0x190 ; =0x190
x8等于0x1008e6190
0x1008e6128 <+52>: ldr x11, [sp]
0x1008e612c <+56>: ldrsw x10, [x8, x11, lsl #2]
從sp寄存器中取出值1存放在x11中
x11中的值1左移2位得到4
x8寄存器的地址+4個字節(jié)得到-24(0xffffffe8)作為地址
存入x10中0xffffffffffffffe8
(lldb) p *(int *)(0x1008e6190 + 4)
(int) $3 = -24
0x1008e6130 <+60>: add x9, x8, x10
x8 + x10 = x9 的地址為0x00000001008e6178刀森,跳入x9
0x1008e6178 <+132>: adrp x0, 1
0x1008e617c <+136>: add x0, x0, #0xf85 ; =0xf85
跳入到default中,得到x0寄存器的地址0x1008e7f85,通過MacOView查看0x1008e7f85的值為E595A5E4B99FE4B88DE5819A
4個漢字“啥也不做”占用12個字節(jié)
輸出default中的內(nèi)容,“啥也不做”
1.前面相減的被減數(shù)是case中的最小值4
2.用最大值和最小值之間的差值8-4=4進(jìn)行比較
3.5-4(最小值)=1 和 8-4=4進(jìn)行比較,若大于,比如a=9抖剿,則在最小值和最大值的區(qū)間外,會大于8,進(jìn)入default
為什么是無符號大于b.hi呢?
舉例腕扶,若case為1 - 4 = -3 脓恕,和4比較
有符號比較,-3小于4,滿足條件秋茫,進(jìn)入case中顯然不符
無符號比較,-3一個超大值枢贿,大于4,跳入default局荚,確保不在區(qū)間范圍內(nèi)的數(shù)跳入default中
為了case的值一定在范圍區(qū)間內(nèi),匯編代碼往下走首装,x8寄存器的地址始終在代碼結(jié)束后的4個字節(jié)仙逻,即代碼后有一張表桨醋,表里面的負(fù)數(shù)個數(shù)為最大值8-最小值4+1(default) = 5個
差值里面的每一個數(shù)都給一個偏移值形成一張表庄蹋,跳轉(zhuǎn)的時候用x8的值直接加上偏移值虫蝶,每個case都是連續(xù)的,表里面的值也是連續(xù)的,表里面地址偏移值連續(xù)
x8 + case4: -24
x8 +4 case5: default -36
x8 +8 case6: -48
x8 +12 case7: -56
x8 +16 case8: -64
偏移值=(case-最小值)左移兩位疼约,即*4,為負(fù)數(shù)
x8寄存器中的地址值+偏移值地址的字節(jié)數(shù)得到x9的地址织鲸,
x8+負(fù)數(shù)等于是x8之前的地址,x8已經(jīng)是匯編代碼的最底部往后了盾饮,x8是表的開始懒熙,偏移表
br直接跳入x9
A.先將參數(shù)減去最小case,無符號大于比較
B.通過表拿到地址,地址運行時才知道虛擬地址普办,如果存地址仍要加上aslr工扎,不如直接用表頭加上偏移值算出,地址也過長
II.case很大,需要連續(xù)衔蹲,相差太大會cmp比較相當(dāng)于if,else結(jié)構(gòu)
3.編譯器優(yōu)化
選擇none不優(yōu)化的時候肢娘,main函數(shù)中的不起作用的變量還在匯編代碼中
若選擇Fastest,Smallest則 int a = 1,b = 2會被編譯器LLVM優(yōu)化掉,刪掉之后對程序的結(jié)果沒有影響,編譯器都會優(yōu)化掉
寫一個函數(shù)舆驶,sum直接被優(yōu)化掉
4.指針:指針的自增自減和執(zhí)行的數(shù)據(jù)類型的寬度有關(guān)
指針的運算單位是執(zhí)行的數(shù)據(jù)類型的寬度
void func(){
int * a;
a = (int *)100;
a++;
printf("%lu",a);
//輸出 104
}
void func0(){
int ** a;
a = (int **)100;
a++;
printf("%d\n",a);
//輸出 108
}
void func1(){
int * a;
a = (int *)100;
int * b;
b = (int *)200;
printf("%d\n",a-b);
//輸出 -25
}
void func2(){
int * a;
a = (int *)100;
int * b;
b = (int *)200;
if(a>b){
printf("a>b\n");
}else{
printf("a<b\n");
}
//輸出 a<b
}
5.指針反匯編
sp+8棧內(nèi)存空間中存放的是sp+4的地址
void func0(){
int arr[5] = {1,2,3,4,5};
int * a = arr;
for (int i = 0; i<sizeof(arr)/sizeof(arr[0]); i++) {
printf("%d",*(a++));
}
//輸出12345
}
Bad Address報錯,從內(nèi)存sp+0x8中取值0賦值給x8,從x8即0這個地址中取值賦值給w9,報錯
二級指針尋址反匯編
兩次中括號尋址lar,指針的指針
二級指針在尋址,