汇编

2021-04-01  本文已影响0人  爱笑的眼睛super

一、编译过程

程序的本质:执行过程

程序在硬盘(010101)->双击->装载进内存


编译

寄存器与内存:

寄存器与内存

编程语言的发展:

发展

汇编语言和机器语言一一对应,每一条机器指令都有与之对应的汇编指令
汇编可以通过编译得到机器语言,机器语言可以通过反汇编得到汇编语言
高级语言可以通过编译得到汇编语言\机器语言,但汇编语言\机器语言机会不可能还原成高级语言

二、汇编基本语法

汇编的种类

x86、x64汇编根据编译器的不同,有2种书写格式

作为iOS开发工程师,最主要的汇编语言是

常见的汇编指令

项目 AT&T 说明
寄存器命名 %rax AT&T寄存器前加%
操作数顺序 movq %rax, %rdx 将rax的值赋值给rdx
常数\立即 数 movq $3, %rax 将3赋值给rax
常数\立即 数 movq $0x10, %rax 将0x10赋值给rax
内存赋值 movq $0xa, 0x1ff7(%rip) 将0xa赋值给地址为rip + 0x1ff7的内存空间
取内存地址 leaq -0x18(%rbp), %rax 将rbp – 0x18这个地址值赋值给rax
jmp指令 jmp *%rdx call和jmp写法类似
jmp 0x4001002
jmp *(%rax)
操作数长度 movl %eax, %edx l = long (32-bit integer or 64-bit floating point)
操作数长度 movb $0x10, %al b = byte (8-bit)
操作数长度 leaw 0x10(%dx), %ax w = word (16-bit)
s = short (16-bit integer or 32-bit floating point)
q = quad (64 bit)

JMP 无条件转移指令
CALL 过程调用 常常伴随着retq 返回

寄存器

有16个常用寄存器
寄存器的具体用途
寄存器的发展过程
64位x86处理器的寄存器.png

64和32位的差异是:
64位有16个寄存器,32位只有8个。但是32位前8个都有不同的命名,分别是e开头,而64位前8个使用了r代替e。e开头的寄存器命名依然可以直接运用于相应寄存器的低32位。而剩下的寄存器名则是从r8 - r15,其低位分别用d,w,b指定长度。
32位使用栈帧来作为传递的参数的保存位置,而64位使用寄存器,分别用rdi,rsi,rdx,rcx,r8,r9作为第1-6个参数。rax作为返回值

三、lldb常用指令

读取寄存器的值
修改寄存器的值
读取内存中的值
修改内存中的值
格式
字节大小
expression 表达式
po 表达式

lldb常用调试指令

四、规律

五、汇编看闭包的本质

step1:证明堆空间里存放着num的值

先看一下没有捕获外部变量这段代码


代码1.png
对应的汇编代码.png

这两个指令的区别:
leaq rip+0x15 rax : 将rip+0x15这个地址给rax
movq rip+0x15 rax : 将rip+0x15这个地址里内容的前8个字节给rax

再看一下这个闭包的代码


代码2.png
对应的汇编代码.png

0x100001b81 <+33>: callq 0x10000724e ; symbol stub for: swift_allocObject

libswiftCore.dylib`swift_allocObject:
0x7fff7241dd22 <+34>: callq 0x7fff7241dc90 ; swift_slowAlloc

libswiftCore.dylib`swift_slowAlloc:

0x7fff7241dca4 <+20>: callq 0x7fff7249a28c ; symbol stub for: malloc
libsystem_malloc.dylib`malloc:
0x7fff72cb7cf0 <+16>: callq 0x7fff72cb7d12 ; malloc_zone_malloc

(lldb) register read rax
rax = 0x000000010062ab90

(lldb) x/5xg 0x000000010062ab90
0x10062ab90: 0x0000000100008150 0x0000000000000002
0x10062aba0: 0x0000000000000000 0x0000000100000000
0x10062abb0: 0x0000000000000000

(lldb) x/5xg 0x000000010062ab90
0x10062ab90: 0x0000000100008150 0x0000000200000002
0x10062aba0: 0x0000000000000001 0x0000000100000000
0x10062abb0: 0x0000000000000000

(lldb) x/5xg 0x000000010062ab90
0x10062ab90: 0x0000000100008150 0x0000000200000002
0x10062aba0: 0x0000000000000009 0x0000000100000000
0x10062abb0: 0x0000000000000000

先看一个例子
猜测swift_allocObject(size_t : size)至少要接收一个参数size,所以找参数,前面也有说过,一般rdi、rsi、rdx、rcx、r8、r9等寄存器常用语存放函数参数
目测这个代码最像,这个参数是告诉堆空间我需要24个字节,但是堆空间的规则分配内存是16的倍数

step2:那么到底分配了多少堆空间的内存呢?fn里放了些什么?

swift_allocObject参数.png
代码3
sum函数地址
汇编代码

计算rip+0xaa4d
和rip+0xaa4a
发现是连续的16个字节,那么fn里前8个字节放的是函数地址,后8个字节放的是0

那么如果捕获外部变量num呢?fn里又放了什么?
根据上面的经验,我们可以知道,我们只需要搞清楚rax,和rdx里放的什么东西,就知道getFn返回的是什么,也就是fn里究竟放了什么

我们来看一下fn这个闭包里放的什么东西呢?
我们在plus这个打个断点,之前说过,一般rax和rdx寄存器放返回值,所有我们看一下rax和rdx放的什么东西?


getFn()

综上所述 我们知道了getFn返回的也就是fn里存放了plus的函数地址和堆空间地址值

step3:plus怎么访问堆空间的num

callq *%rax

fn(1)
fn(8)
我们之前说过,一般参数是放到di、rsi、rdx、rcx、r8、r9等这个寄存器里,所以看
move $0x8 %edi
plus(i, heap num堆控件的地址值) // rdx+0x10

plus参数.png

rdi->1
r13->rsi->堆空间地址值


addq

add 0x10(%rdx), %rcx
rcx = num + rcx

rcx送回num地址里

附:


附1 附2
上一篇 下一篇

猜你喜欢

热点阅读