全局变量
内存的分区
- 代码区
- 存放代码
- 可读可执行
- 常量区
- 只读
- 全局变量区
- 可读可写
- 堆区
- alloc 开辟的是堆空间 想系统申请,动态申请
- 可读可写
- 栈区 函数调用栈
- 参数 局部变量 临时数据
- 可读可写
PS: 是编译器在编译阶段做的。是逻辑上面的区分。读取的时候按照区域读取。
测试全局变量
int g = 12;
int func(int a, int b) {
printf("haha");
int c = a + g;
return c;
}
func(1, 2);
复制代码
Demo`func:
0x10255a120 <+0>: sub sp, sp, #0x20 ; =0x20
0x10255a124 <+4>: stp x29, x30, [sp, #0x10]
0x10255a128 <+8>: add x29, sp, #0x10 ; =0x10
0x10255a12c <+12>: stur w0, [x29, #-0x4]
0x10255a130 <+16>: str w1, [sp, #0x8]
0x10255a134 <+20>: adrp x0, 1
0x10255a138 <+24>: add x0, x0, #0xf85 ; =0xf85
-> 0x10255a13c <+28>: bl 0x10255a598 ; symbol stub for: printf
0x10255a140 <+32>: ldur w8, [x29, #-0x4]
0x10255a144 <+36>: adrp x9, 3
0x10255a148 <+40>: add x9, x9, #0x5e8 ; =0x5e8
0x10255a14c <+44>: ldr w10, [x9]
0x10255a150 <+48>: add w8, w8, w10
0x10255a154 <+52>: str w8, [sp, #0x4]
0x10255a158 <+56>: ldr w8, [sp, #0x4]
0x10255a15c <+60>: mov x0, x8
0x10255a160 <+64>: ldp x29, x30, [sp, #0x10]
0x10255a164 <+68>: add sp, sp, #0x20 ; =0x20
0x10255a168 <+72>: ret
复制代码
数字和字符的对应关系
68 61 68 61 00 54 40 22 55 49 57 69 6e 64 6f 77
h a h a . T @ " U I W i n d o w
复制代码
adrp
- Address page 按页寻址
0x10255a134 <+20>: adrp x0, 1 将1的值左移12位
复制代码
如果是2, 就是将2左移12位
- 上面的指令有三个含义
- 将1左移12位 0x1000
- 将pc寄存器的值0x10255a134,低12位清零 0x10255a000
- 0x1000 + 0x10255a000 = 0x10255b000 = x0
0x10255a138 <+24>: add x0, x0, #0xf85 ; =0xf85
复制代码
将x0寄存器的低12位设置位0xf85 0x10255b000 + 0xf85 = 0x10255bf85
低12位的最到值是0xfff = 4095
终端输入
PAGESIZE
复制代码
一个页的大小
0x10255a000 是某一页的位置
0xf85 是偏移量
PS: 手机的page size 是0x4000 = 16k, 不是0x1000
PS: 参照pc寄存器,即当前代码段的代码地址
全局参数g的寻址
反汇编
0000000100006118 sub sp, sp, #0x20 ; CODE XREF=_main+64
000000010000611c stp x29, x30, [sp, #0x10]
0000000100006120 add x29, sp, #0x10
0000000100006124 stur w0, [x29, #-0x4]
0000000100006128 str w1, [sp, #0x8]
000000010000612c adrp x0, #0x100007000 ; argument #1 for method imp___stubs__printf
0000000100006130 add x0, x0, #0xf85 ; "haha"
0000000100006134 bl imp___stubs__printf
0000000100006138 ldur w8, [x29, #-0x4]
000000010000613c adrp x9, #0x100009000
0000000100006140 add x9, x9, #0x5e8 ; _g
0000000100006144 ldr w10, x9
0000000100006148 add w8, w8, w10
000000010000614c ldr w10, [sp, #0x8]
0000000100006150 add w8, w8, w10
0000000100006154 str w8, [sp, #0x4]
0000000100006158 ldr w8, [sp, #0x4]
000000010000615c mov x0, x8
0000000100006160 ldp x29, x30, [sp, #0x10]
0000000100006164 add sp, sp, #0x20
0000000100006168 ret
复制代码
循环 & 选择
if
int g = 12;
void func(int a, int b) {
if (a > b) {
g = a;
} else {
g = b;
}
}
func(1, 2);
复制代码
将真机编译的Mach-O文件拖到Hopper
反汇编代码
================ B E G I N N I N G O F P R O C E D U R E ================
_func:
0000000100006144 sub sp, sp, #0x10 ; 拉伸栈空间
0000000100006148 str w0, [sp, #0xc] ;a入栈
000000010000614c str w1, [sp, #0x8] ;b入栈
0000000100006150 ldr w8, [sp, #0xc] ;w8 = a
0000000100006154 ldr w9, [sp, #0x8] ;w9 = b
0000000100006158 cmp w8, w9 ;com 执行的是减法 不影响w8和w9 只修改标记寄存器
000000010000615c b.le loc_100006174 ; b是跳转,le是 <= 。如果小于等于 就跳转,如果大于就继续执行
1 段
0000000100006160 ldr w8, [sp, #0xc] ;将栈中的参数a赋值给w8
0000000100006164 adrp x9, #0x100009000
0000000100006168 add x9, x9, #0x5e0 ; _g 在全局变量区找到全局变量 g,并将地址赋值给x9
000000010000616c str w8, x9 ;将w8的值存储到w9,即全局变量区,w9保存的是地址
0000000100006170 b loc_100006184 ;不改变lr寄存器 直接跳转
2 段
loc_100006174:
0000000100006174 ldr w8, [sp, #0x8] ; 将栈中的参数b赋值给w8
0000000100006178 adrp x9, #0x100009000
000000010000617c add x9, x9, #0x5e0 ; _g 在全局变量区找到全局变量 g,并将地址赋值给x9
0000000100006180 str w8, x9 ;将w8的值存储到w9,即全局变量区,w9保存的是地址
3 段
loc_100006184:
0000000100006184 add sp, sp, #0x10 ; CODE XREF=_func+44
0000000100006188 ret
; endp
; ================ B E G I N N I N G O F P R O C E D U R E
复制代码
如果 w8 – w9 <= 0,执行 2 3段,否则执行 1 3段
cmp(Compare)比较指令
CMP把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志
一般CMP做完判断后会进行跳转,后面通常会跟上b指令!
- BL标号: 跳转到标号处执行
- B.LT标号: 比较结果是小于(less), 执行标号, 否则不跳转
- B.LE标号: 比较结果是小于等于(less equal), 执行标号, 否则不跳转
- B.GT标号: 比较结果是大于(greater than), 执行标号,否则不跳转
- B.GE标号: 比较结果是大于等于(greater than or equal to),执行标号,否则不跳转
- B.EQ标号: 比较结果是等于, 执行标号, 否则不跳转
- B.NE标号: 比较结果是不等于, 执行标号, 否则不跳转
- B.LS标号: 比较结果是无符号小于等于,执行标号, 否则跳转
- B.LO标号: 比较结果是无符号小于,执行标号, 否则跳转
- B.HI标号: 比较结果是无符号大于,执行标号, 否则跳转
- B.HS标号: 比较结果是无符号大于等于,执行标号, 否则跳转
循环
do while
int nSum = 0;
int i = 0;
do {
nSum = nSum + 1;
i++;
} while (i < 100);
复制代码
反汇编代码
; ================ B E G I N N I N G O F P R O C E D U R E ================
_main:
0000000100006174 sub sp, sp, #0x50
0000000100006178 stp x29, x30, [sp, #0x40]
000000010000617c add x29, sp, #0x40
0000000100006180 movz x8, #0x0
0000000100006184 stur wzr, [x29, #-0x4]
0000000100006188 stur w0, [x29, #-0x8]
000000010000618c stur x1, [x29, #-0x10]
0000000100006190 stur x8, [x29, #-0x18]
0000000100006194 bl imp___stubs__objc_autoreleasePoolPush
0000000100006198 stur wzr, [x29, #-0x1c] ; 将0入栈 即aSum = 0
000000010000619c str wzr, [sp, #0x20] ; 将0入栈 即i = 0
00000001000061a0 str x0, [sp, #0x18]
loc_1000061a4:
00000001000061a4 ldur w8, [x29, #-0x1c] ; CODE XREF=_main+80 ;将aSum的值放到寄存器w8
00000001000061a8 add w8, w8, #0x1 ;将w8寄存器的值加一
00000001000061ac stur w8, [x29, #-0x1c];将w8入栈
上面三步是 aSum = aSum + 1
00000001000061b0 ldr w8, [sp, #0x20] ;将i的值读取到w8
00000001000061b4 add w8, w8, #0x1 ; 将w8的值加一
00000001000061b8 str w8, [sp, #0x20] ; 将w8的值入栈
上面三步是 i++
00000001000061bc ldr w8, [sp, #0x20] ; 将i的值保存到w8
00000001000061c0 cmp w8, #0x64 ; w8 - 100
00000001000061c4 b.lt loc_1000061a4 ; 如果cmp的结果小于0,
跳转到loc_1000061a4 继续执行循环
上面三步是 while( i < 100)
复制代码
先执行 再判断
while代码
int nSum = 0;
int i = 0;
while (i < 100) {
nSum = nSum + 1;
i++;
}
复制代码
; ================ B E G I N N I N G O F P R O C E D U R E ================
_main:
0000000100006170 sub sp, sp, #0x50
0000000100006174 stp x29, x30, [sp, #0x40]
0000000100006178 add x29, sp, #0x40
000000010000617c movz x8, #0x0
0000000100006180 stur wzr, [x29, #-0x4]
0000000100006184 stur w0, [x29, #-0x8]
0000000100006188 stur x1, [x29, #-0x10]
000000010000618c stur x8, [x29, #-0x18]
0000000100006190 bl imp___stubs__objc_autoreleasePoolPush
0000000100006194 stur wzr, [x29, #-0x1c]
0000000100006198 str wzr, [sp, #0x20]
000000010000619c str x0, [sp, #0x18]
loc_1000061a0:
00000001000061a0 ldr w8, [sp, #0x20] ; 将i读取到寄存器w8
00000001000061a4 cmp w8, #0x64 ; w8 - 100
00000001000061a8 b.ge loc_1000061c8 ; 比较cmp的结果,如果结果大于等于 0,跳转到loc_1000061c8执行。否则继续向下执行,也就是继续循环
上面三句是 while(i < 100)
先判断 在执行
00000001000061ac ldur w8, [x29, #-0x1c]
00000001000061b0 add w8, w8, #0x1
00000001000061b4 stur w8, [x29, #-0x1c]
00000001000061b8 ldr w8, [sp, #0x20]
00000001000061bc add w8, w8, #0x1
00000001000061c0 str w8, [sp, #0x20]
00000001000061c4 b loc_1000061a0 ; 跳转到上面, 进行cmp的比较
loc_1000061c8:
00000001000061c8 adrp x8, #0x100009000 ; CODE XREF=_main+56
复制代码
PS 先判断 在执行
for
和 while是一样的, 所有两个会相互转换
Switch
- 假设switch语句分支比较少的时候(例如3,少于4的时候没有意义) 没有必要使用此结果,相当于if
- 各个分支的常量的差值较大的时候, 编译器会在效率还是在内存进行取舍, 这个时候编译器还是会编译成类似if、else的结果
- 在分支比较多的时候: 在编译的时候会生成一个表(跳转表每个地址四个字节)
int funcA(int a) {
switch (a) {
case 1:
printf("打坐");
break;
case 2:
printf("加红");
break;
case 3:
printf("加蓝");
break;
default:
printf("什么都不干");
break;
}
return 0;
}
复制代码
反汇编代码
多加一个case
int funcA(int a) {
switch (a) {
case 1:
printf("打坐");
break;
case 2:
printf("加红");
break;
case 3:
printf("加蓝");
break;
case 4:
printf("打怪");
break;
default:
printf("什么都不干");
break;
}
return 0;
}
复制代码
建立一张数据表
case的值没有规律
int funcA(int a) {
switch (a) {
case 1:
printf("打坐");
break;
case 200:
printf("加红");
break;
case 35:
printf("加蓝");
break;
case 41:
printf("打怪");
break;
default:
printf("什么都不干");
break;
}
return 0;
}
复制代码
总结 循环选择判断
- 全局变量和常量
- 获取全局变量和常量时,会出现adrp和add两条指令获取一个地址的情况
- adrp (address page)
- adrp x0, 1
- 将pc寄存器的低12位清零
- 将1的值,左移12位,16进制就是0x100
- 将以上两个结果相加放入x0寄存器
- 通过add指令获取这页内存中的偏移值 4096 4k
- if
- com指令 比较
- cmp其实在做减法,然后不影响目标寄存器,值影响标记寄存器
- subs\adds等 影响目标寄存器和状态寄存器
- 循环
- do while循环: 判断条件在后面, 满足条件往外跳
- for 循环和while循环很像, 判断条件在里面,不满足条件往外跳
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END