ARM汇编(4)-指针

  目录

1. 指针

指针也就是内存地址,指针变量是用来存放内存地址的变量。不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。
可使用 & 运算符访问地址。

之前的文章中有过说明,指针在内存中占8个字节。
可以是用sizeof来打印指针的size。

void func() {
    int *a;
    a = (int *)100;
    a ++;
    printf("%d", a);
}

这里定义一个int类型的指针a,然后赋值位100,我们知道指针的size是8个字节,a++之后打印多少?

答案是104。是的,没有看错,这里是因为指针的自增和自减操作,与执行的数据类型的宽度有关。

如果a = (char *)100,则打印的就是101。

void func() {
    int *a;
    a = (int *)100;
    a = a + 1;
    printf("%d", a);
}

这个不是指针的自增、自减了,这个时候就跟指针的size有关了,打印108。

void func_add() {
    int *a;
    a = (int *)100;
    
    int *b;
    b = (int *)200;
    
    int x = a - b;
    printf("x = %d", x);
}

先说答案,打印的结果是x = -25

a - b = -100, 然后除以4就得到了这个结果。

指针的运算单位是执行的数据类型的宽度。

1.1 二级指针

void func() {
    int **a;
    a = (int **)100;
    a = a + 1;
    printf("%d", a);
}

这个时候a运算时,执行的类型就是 char *类型,这是一个指针,8个字节。所以结果就是108。

2. 指针的汇编

void func() {
    int *a;
    int b = 10;
    a = &b;
}

按照我们正常的理解,上述代码的意思就是把b的地址给到a,这个时候*a=10

看一下上面的代码汇编之后是什么样子的。

Demo`func:
    0x100206130 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    // 1. x8 = sp + 0x4,x8指向这个位置
    0x100206134 <+4>:  add    x8, sp, #0x4              ; =0x4 
    // 2. 局部变量,w9=10
    0x100206138 <+8>:  mov    w9, #0xa
    // 3. 把w9的值放在x8所在的地址上。
    0x10020613c <+12>: str    w9, [sp, #0x4]
    // 4. 把x8存储的地址放在sp + 0x8的位置上。
->  0x100206140 <+16>: str    x8, [sp, #0x8]
    0x100206144 <+20>: add    sp, sp, #0x10             ; =0x10 
    0x100206148 <+24>: ret    

通过lldb打印一下相关数据:

(lldb) register read sp
      sp = 0x000000016fbff880

(lldb) register read x8
      x8 = 0x000000016fbff884
   
(lldb) register read x9
      x9 = 0x000000000000000a

// 打印一下x8寄存器里的内存地址情况,里头存的值是0xa
(lldb) x 0x000000016fbff884
0x16fbff884: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x16fbff894: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................   

// x8的地址放在了sp+0x8的位置,打印一下内存,就是x8存储的地址。
(lldb) x 0x000000016fbff888
0x16fbff888: 84 f8 bf 6f 01 00 00 00 00 00 00 00 00 00 00 00  ...o............
0x16fbff898: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

2.1 数组

void func() {
    int arr[5] = {1,2,3,4,5};
    for (int i = 0; i < 5; i++) {
        printf("%d\n", *(arr + i));
    }
}

2.2 野指针

void func() {
    char *p;
    char a = *p;
}

通过代码,我们知道,只是把*p的值给了a
为什么会发生野指针呢?

Demo`func:
    0x100812134 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    // 1. 因为p是指针。把sp + 0x8的地址中的值给x8
->  0x100812138 <+4>:  ldr    x8, [sp, #0x8]
    // 2. 把x8寄存器中存的地址的值给w9
    0x10081213c <+8>:  ldrb   w9, [x8]
    0x100812140 <+12>: strb   w9, [sp, #0x7]
    0x100812144 <+16>: add    sp, sp, #0x10             ; =0x10 
    0x100812148 <+20>: ret    
  1. 第一步寻址操作,获取x8寄存器的值的地址
(lldb) register read sp
      sp = 0x000000016f5f3880

// sp + 0x8 = 0x000000016f5f3888
(lldb) x 0x000000016f5f3888
0x16f5f3888: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x16f5f3898: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

(lldb) register read x8
  x8 = 0x0000000000000000
这里发现 x8寄存器中存的地址是空,全是0。
  1. 把x8寄存器中地址所在的值给w9。寻址操作
    这里寻址是从0x00000000上找值,从空地址上找值,就会发生crash。

文章作者: 改变世界
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 改变世界 !
评论