全局变量

全局变量

内存的分区

  • 代码区
    • 存放代码
    • 可读可执行
  • 常量区
    • 只读
  • 全局变量区
    • 可读可写
  • 堆区
    • 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    

复制代码

WeChat7af70c8bf4843b366aa3e148ef04068a.png

数字和字符的对应关系

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位
复制代码

WeChat4ad4d0cdd9d6c022c6b22d3fc3db415b.png

如果是2, 就是将2左移12位

WeChatd3af774abae163c043bc7fe76da236b2.png

  • 上面的指令有三个含义
    • 将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

WeChatc08157d14321d6e83bec11c01551c13d.png

WeChatc7f598ccbffa446d5fb122df5fdf2ea9.png

终端输入

PAGESIZE
复制代码

WeChatbb9054797c4857d487437d1caedce456.png

一个页的大小

0x10255a000 是某一页的位置
0xf85 是偏移量

PS: 手机的page size 是0x4000 = 16k, 不是0x1000
PS: 参照pc寄存器,即当前代码段的代码地址

全局参数g的寻址

WeChateb96e77ad76f766ddd4819052f20d007.png

反汇编

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

WeChat412106332b5c6471a3ce52e6ab0aec23.png

反汇编代码

================ 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);
复制代码

反汇编代码

WeChat6dbc43f2138de26199b84a0fcbabd38c.png

 ; ================ 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++;
}
复制代码

WeChat60dd44c4d542c1155f02f578bb4eac20.png

  ; ================ 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

WeChat8259097fdde80b5672f3741b761c611f.png

和 while是一样的, 所有两个会相互转换

Switch

  1. 假设switch语句分支比较少的时候(例如3,少于4的时候没有意义) 没有必要使用此结果,相当于if
  2. 各个分支的常量的差值较大的时候, 编译器会在效率还是在内存进行取舍, 这个时候编译器还是会编译成类似if、else的结果
  3. 在分支比较多的时候: 在编译的时候会生成一个表(跳转表每个地址四个字节)
int funcA(int a) {
    switch (a) {
        case 1:
            printf("打坐");
            break;
        case 2:
            printf("加红");
            break;
        case 3:
            printf("加蓝");
            break;
            
        default:
            printf("什么都不干");
            break;
    }
    return 0;
}

复制代码

WeChate3094f738ebc390ba870d3202b7c448a.png

反汇编代码

WeChata3315b644a7050633d193737d237c280.png

多加一个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;
}
复制代码

WeChat6c0f29c9f01d1295a1862f89c5e2b774.png

建立一张数据表

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;
}
复制代码

WeChatd4dabe43ba12e69f00f7731828fd4bb3.png

总结 循环选择判断

  • 全局变量和常量
    • 获取全局变量和常量时,会出现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
喜欢就支持一下吧
点赞0 分享