汇编看指针

您所在的位置:网站首页 指针的英文是什么怎么读出来 汇编看指针

汇编看指针

2024-07-10 13:50| 来源: 网络整理| 查看: 265

前言

我们都知道 可以使用指针间接的去获取或者修改某个变量的值, 那么指针到底是什么?编译器是怎么翻译指针代码, 或者说指针在汇编层面到底是什么, 用汇编去分析模棱两可的知识 可以看到知识的底层和本质 能加深我们对事物的认知深度。

mov 和 lea 指令

汇编看指针离不开这两个指令先看下mov指令

mov指令

GNU–> AT&T汇编 强制要求 mov 指令指定长度 因此,指令就变成了如下:movx 其中 x 可以是下面的字符: 1,q用于64位的4字值 2,l用于32位的长字值 3,w用于16位的字值 4,b用于8位的字节值

源码 - (void)asm_point { int a = 6; } AT&T汇编

GUN汇编器输出AT&T汇编 和 Intel 汇编的语法顺序是相反

YangASM`-[ViewController asm_point]: 0x10ed88ee0 : pushq %rbp 0x10ed88ee1 : movq %rsp, %rbp 0x10ed88ee4 : movq %rdi, -0x8(%rbp) 0x10ed88ee8 : movq %rsi, -0x10(%rbp) 0x10ed88eec : movl $0x6, -0x14(%rbp) -> 0x10ed88ef3 : popq %rbp 0x10ed88ef4 : retq 汇编转化内存地址 (lldb) p &a (int *) $4 = 0x00007ffee0e7503c (lldb) register read rbp rbp = 0x00007ffee0e75050 (lldb) p/x 0x00007ffee0e75050-0x8 (long) $5 = 0x00007ffee0e75048 (lldb) p/x 0x00007ffee0e75050-0x10 (long) $6 = 0x00007ffee0e75040 (lldb) p/x 0x00007ffee0e75050-0x14 (long) $7 = 0x00007ffee0e7503c (lldb) 分析 ```c YangASM`-[ViewController asm_point]: // rbp = 0x00007ffee0e75050 // 开启asm_point 函数的函数栈 0x10ed88ee0 : pushq %rbp 0x10ed88ee1 : movq %rsp, %rbp // 上面我们得到 -0x8(%rbp) p/x 0x00007ffee0e75050-0x8 = 0x00007ffee0e75048 // 从 movq 可以看出来 需要霸占内存8个字节的区间 // 那么这条指令就是 rdi的值存放到 从0x00007ffee0e75048开始 往下的8个字节内 0x10ed88ee4 : movq %rdi, -0x8(%rbp) // rsi的值存放到 从0x00007ffee0e75040开始 往后的8个字节内 0x10ed88ee8 : movq %rsi, -0x10(%rbp) // int a = 6 6被成为立即数 可以不借助寄存器 直接写入内存 // 把6存放到 从0x00007ffee0e7503c往下4个字节的区间内 // movl 看到需要霸占4个字节区间 int类型 4个字节 0x10ed88eec : movl $0x6, -0x14(%rbp) // 回收asm_point函数的函数栈空间 -> 0x10ed88ef3 : popq %rbp 0x10ed88ef4 : retq

上面的汇编有movl 和 movq 也就是说 在 AT&T汇编中 mov指令都是以movx的形式出现

movx 指令帮我们做了

把立即数直接写入内存把数据从内存传递给寄存器把数据从寄存器传递给内存使用寄存器间接寻址 使用寄存器间接寻址

除了保存数据之外,寄存器还可以用于保存内存地址 当寄存器保存内存地址时,它被称为指针。 使用指针访问存储在内存位置中的数据称为间接寻址。

上面的汇编中 movq %rdi, -0x8(%rbp) 还有内括号 还有 - 号

分别含义如下:

movl %ebx, %edi ebx寄存器中的值 加载到edi寄存器中

movl %ebx, (%edi) edi加上内括号 就是把 ebx寄存器中的值传递给 edi寄存器中包含的内存地址

movl %ebx, 4(%edi) 把edx寄存器中的值存放到edi寄存器指向的位置之后的4个字节的内存位置中

也可以把它存放到相反的方向 movl %ebx, -4(%edi) 把edx寄存器中的值存放到edi寄存器指向的位置之前的4个字节的内存位置中

内存布局:

上面的汇编代码 绘制出内存布局如下

leq 指令

leq 后面跟地址 直接把地址 给寄存器 mov 后面跟地址 把地址上的数据 给寄存器 两个指令配合使用 可以完成指针

源码 - (void)asm_point { int a = 6; int *p = a; } 汇编 YangASM`-[ViewController asm_point]: 0x10da42ee0 : pushq %rbp 0x10da42ee1 : movq %rsp, %rbp // 安排 rdi rsi 0x10da42ee4 : movq %rdi, -0x8(%rbp) 0x10da42ee8 : movq %rsi, -0x10(%rbp) // int a = 6 6存入 -0x14(%rbp) 0x10da42eec : movl $0x6, -0x14(%rbp) // 讲-0x14(%rbp)这个地址 赋给rax 0x10da42ef3 : leaq -0x14(%rbp), %rax // rax里面的值 存入-0x20(%rbp) // rax里面的值 是一个地址 -0x14(%rbp) 0x10da42ef7 : movq %rax, -0x20(%rbp) -> 0x10da42efb : popq %rbp 0x10da42efc : retq

重点看这两行汇编

leaq -0x14(%rbp), %rax movq %rax, -0x20(%rbp)

看到这样的组合 就应该知道是指针 -0x14(%rbp) 就是指针指向的地址 -0x20(%rbp) 就是指针自己的地址 %rax, -0x20(%rbp) 就是把指针指向的地址 存储的自己的内存空间里面

如果是 intel汇编的话 我们模拟写2行 应该是这样

lea eax, [ebp-och] // dword ptr 8字节长度 mov dword ptr 等价上面的 movq 8字节 mov dword ptr [ebp-18h], eax

在结合图示看下 请添加图片描述

指针修改变量值

了解完 leq 和 mov 我们看指针修改

- (void)asm_point { int a = 6; int *p = &a; *p = 12; } 汇编 YangASM`-[ViewController asm_point]: 0x10f5e4ed0 : pushq %rbp 0x10f5e4ed1 : movq %rsp, %rbp 0x10f5e4ed4 : movq %rdi, -0x8(%rbp) 0x10f5e4ed8 : movq %rsi, -0x10(%rbp) 0x10f5e4edc : movl $0x6, -0x14(%rbp) 0x10f5e4ee3 : leaq -0x14(%rbp), %rax 0x10f5e4ee7 : movq %rax, -0x20(%rbp) 0x10f5e4eeb : movq -0x20(%rbp), %rax 0x10f5e4eef : movl $0xc, (%rax) -> 0x10f5e4ef5 : popq %rbp 0x10f5e4ef6 : retq 内存地址 (lldb) register read rbp rbp = 0x00007ffee0619050 (lldb) p/x 0x00007ffee0619050-0x8 (long) $5 = 0x00007ffee0619048 (lldb) p/x 0x00007ffee0619050-0x10 (long) $6 = 0x00007ffee0619040 (lldb) p/x 0x00007ffee0619050-0x14 (long) $7 = 0x00007ffee061903c (lldb) p/x 0x00007ffee0619050-0x20 (long) $8 = 0x00007ffee0619030 (lldb) 内存布局

图一

// 安排 rsi rdi 0x10f5e4ed4 : movq %rdi, -0x8(%rbp) 0x10f5e4ed8 : movq %rsi, -0x10(%rbp)

图二

// int a = 6 6存入 -0x14(%rbp) 0x10f5e4edc : movl $0x6, -0x14(%rbp)

图三

0x10f5e4ee7 : movq %rax, -0x20(%rbp)

图四

0x10f5e4ee7 : movq %rax, -0x20(%rbp) 0x10f5e4eef : movl $0xc, (%rax) 完整汇编分析 YangASM`-[ViewController asm_point]: 0x10f5e4ed0 : pushq %rbp 0x10f5e4ed1 : movq %rsp, %rbp // 安排 rdi rsi 0x10f5e4ed4 : movq %rdi, -0x8(%rbp) 0x10f5e4ed8 : movq %rsi, -0x10(%rbp) // int a = 6 6存入 -0x14(%rbp) 0x10f5e4edc : movl $0x6, -0x14(%rbp) // 讲-0x14(%rbp)这个地址 赋给rax 0x10f5e4ee3 : leaq -0x14(%rbp), %rax // rax里面的值 存入-0x20(%rbp) 0x10f5e4ee7 : movq %rax, -0x20(%rbp) // 讲-0x20(%rbp)的值赋给rax rax 现在指向-0x20(%rbp) // 这个地方很容易让人疑问 上面刚刚把rax 存入内存 怎么有从内存取出来了? // 上面的存入内存是因为源码的 int *p = &a 汇编要完成 p指向一个地址 // 这里是因为代码中 出现了 *p = 12 // *p = 12 其实是2行汇编代码 首先取到 *p 另一行是赋12 // 这里是为了后面 取(rax)提供方便 0x10f5e4eeb : movq -0x20(%rbp), %rax // (%rax) rax加一个内括号 就是操作这块内存区域里面的值 // movl 说明是4个字节 // 讲 这块区域的值改成 12 0xc 0x10f5e4eef : movl $0xc, (%rax) -> 0x10f5e4ef5 : popq %rbp 0x10f5e4ef6 : retq


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3