Java教程

汇编看指针

本文主要是介绍汇编看指针,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

开发中经常使用指针访问变量修改变量值, 那么编译器是怎么翻译指针的 或者说指针在汇编层面到底是什么

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 <+0>:  pushq  %rbp
    0x10ed88ee1 <+1>:  movq   %rsp, %rbp
    0x10ed88ee4 <+4>:  movq   %rdi, -0x8(%rbp)
    0x10ed88ee8 <+8>:  movq   %rsi, -0x10(%rbp)
    0x10ed88eec <+12>: movl   $0x6, -0x14(%rbp)
->  0x10ed88ef3 <+19>: popq   %rbp
    0x10ed88ef4 <+20>: 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 <+0>:  pushq  %rbp
    0x10ed88ee1 <+1>:  movq   %rsp, %rbp
    // 上面我们得到 -0x8(%rbp)  p/x 0x00007ffee0e75050-0x8  = 0x00007ffee0e75048
    // 从 movq 可以看出来 需要霸占内存8个字节的区间
   	// 那么这条指令就是 rdi的值存放到 从0x00007ffee0e75048开始 往下的8个字节内
    0x10ed88ee4 <+4>:  movq   %rdi, -0x8(%rbp)
    
    // rsi的值存放到 从0x00007ffee0e75040开始 往后的8个字节内
    0x10ed88ee8 <+8>:  movq   %rsi, -0x10(%rbp)
    
    // int a = 6
    // 把6存放到 从0x00007ffee0e7503c往下4个字节的区间内
    // movl 看到需要霸占4个字节区间   int类型 4个字节 
    0x10ed88eec <+12>: movl   $0x6, -0x14(%rbp)
    
    // 回收asm_point函数的函数栈空间
->  0x10ed88ef3 <+19>: popq   %rbp
    0x10ed88ef4 <+20>: retq  

上面的汇编有movl 和 movq

也就是说 在 AT&T汇编中 mov指令都是以movx的形式出现

间接寻址

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

分别含义如下:

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

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

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

  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 <+0>:  pushq  %rbp
    0x10da42ee1 <+1>:  movq   %rsp, %rbp

    // 安排 rdi rsi
    0x10da42ee4 <+4>:  movq   %rdi, -0x8(%rbp)
    0x10da42ee8 <+8>:  movq   %rsi, -0x10(%rbp)

    // int a = 6   6存入 -0x14(%rbp)
    0x10da42eec <+12>: movl   $0x6, -0x14(%rbp)

    // 讲-0x14(%rbp)这个地址 赋给rax
	0x10da42ef3 <+19>: leaq   -0x14(%rbp), %rax

    // rax里面的值 存入-0x20(%rbp)
    // rax里面的值 是一个地址 -0x14(%rbp)  
    0x10da42ef7 <+23>: movq   %rax, -0x20(%rbp)
    
->  0x10da42efb <+27>: popq   %rbp
    0x10da42efc <+28>: retq  

指针修改变量值

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

- (void)asm_point {
    int a = 6;
    int *p = &a;
    *p = 12;
}

汇编

YangASM`-[ViewController asm_point]:
    0x10f5e4ed0 <+0>:  pushq  %rbp
    0x10f5e4ed1 <+1>:  movq   %rsp, %rbp
    0x10f5e4ed4 <+4>:  movq   %rdi, -0x8(%rbp)
    0x10f5e4ed8 <+8>:  movq   %rsi, -0x10(%rbp)
    0x10f5e4edc <+12>: movl   $0x6, -0x14(%rbp)
    0x10f5e4ee3 <+19>: leaq   -0x14(%rbp), %rax
    0x10f5e4ee7 <+23>: movq   %rax, -0x20(%rbp)
    0x10f5e4eeb <+27>: movq   -0x20(%rbp), %rax
    0x10f5e4eef <+31>: movl   $0xc, (%rax)
->  0x10f5e4ef5 <+37>: popq   %rbp
    0x10f5e4ef6 <+38>: 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 <+4>:  movq   %rdi, -0x8(%rbp)
 0x10f5e4ed8 <+8>:  movq   %rsi, -0x10(%rbp)

请添加图片描述

图二

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

请添加图片描述

图三

0x10f5e4ee7 <+23>: movq   %rax, -0x20(%rbp)   

请添加图片描述

图四

 0x10f5e4ee7 <+23>: movq   %rax, -0x20(%rbp)
 0x10f5e4eef <+31>: movl   $0xc, (%rax)  

请添加图片描述

完整汇编分析

YangASM`-[ViewController asm_point]:
    0x10f5e4ed0 <+0>:  pushq  %rbp
    0x10f5e4ed1 <+1>:  movq   %rsp, %rbp
    // 安排 rdi rsi
    0x10f5e4ed4 <+4>:  movq   %rdi, -0x8(%rbp)
    0x10f5e4ed8 <+8>:  movq   %rsi, -0x10(%rbp)

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

    // 讲-0x14(%rbp)这个地址 赋给rax
    0x10f5e4ee3 <+19>: leaq   -0x14(%rbp), %rax

    // rax里面的值 存入-0x20(%rbp)
    0x10f5e4ee7 <+23>: movq   %rax, -0x20(%rbp)   

    // 讲-0x20(%rbp)的值赋给rax   rax 现在指向-0x20(%rbp)  
    // 这个地方很容易让人疑问 上面刚刚把rax 存入内存  怎么有从内存取出来了?
    // 上面的存入内存是因为源码的 int *p = &a  汇编要完成 p指向一个地址
    // 这里是因为代码中 出现了 *p = 12  
    // *p = 12 其实是2行汇编代码  首先取到 *p  另一行是赋12   
    // 这里是为了后面 取(rax)提供方便  
    0x10f5e4eeb <+27>: movq   -0x20(%rbp), %rax

   
    // (%rax)  rax加一个内括号  就是操作这块内存区域里面的值  
    // movl 说明是4个字节 
    // 讲 这块区域的值改成 12  0xc  
    0x10f5e4eef <+31>: movl   $0xc, (%rax)


->  0x10f5e4ef5 <+37>: popq   %rbp
    0x10f5e4ef6 <+38>: retq  

这篇关于汇编看指针的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!