汇编语言
语言流程
高级语言 -> 汇编语言 -> 机器语言 -> 计算机
- 高级语言:例如swift,java
- 汇编语言:movq %rax %rdi
- 机器语言:1001010100101
总结:汇编语言与机器语言是一一对应的,汇编语言可以通过编译得到机器语言,机器语言也可以通过反汇编得到汇编语言。
iOS主要汇编语言
- AT&T汇编:iOS模拟器
- ARM汇编:iOS真机设备
不管是那种,都是具有通用性的。
常见的汇编指令
- movq:常数或者内存赋值。 如:movq %rax, %rdx,意思是把rax寄存器的值赋值给rdx。由如 movq %rax, 0x1fd3(%rbp) ,意思是把 rax的值 赋值给地址为 rbp + 0x1fd3的内存空间。
- leaq:内存地址。如: leaq 0x17bd(%rip), %rdi,意思是把rip + 0x17bd的地址值赋值给rdi。
- callq: 函数。如:callq 0x100003af0,进入内存为0x100003af0的函数。
- jump:跳转。如:jmp 0x100002703,跳到内存为0x100002703的那一列。
- retq:返回。一般进入callq里面,都有retq来结束函数。
- addq:加法。如addq %rcx, %rax,意思是rcx的值加上rax的值。
LLDB常用指令
- register read %rdi,或者register read,可以读取某个寄存器的值或者所有寄存器的值
- register write %rdi 0 ,修改rdi寄存器的值为0
- x/4xg 0x00000001000083e8 ,读取数量为4个,8个字节的内存的值
- n或者ni:源码/汇编的下一步,不进入子函数。
- s或者si:源码/汇编的下一步,遇到子函数call,会进入。
- finish:cal到子函数里面,跳出来子函数就finish。
窥探枚举内存
面试考题
enum TestEnum1 {
case test1(Int, Int, Int)
}
print(MemoryLayout<TestEnum1>.size)
print(MemoryLayout<TestEnum1>.stride)
print(MemoryLayout<TestEnum1>.alignment)
enum TestEnum2 {
case test1,test2,test3
}
print(MemoryLayout<TestEnum2>.size)
print(MemoryLayout<TestEnum2>.stride)
print(MemoryLayout<TestEnum2>.alignment)
enum TestEnum3 {
case test1(Int, Int, Int)
case test2,test3,test4
}
print(MemoryLayout<TestEnum3>.size)
print(MemoryLayout<TestEnum3>.stride)
print(MemoryLayout<TestEnum3>.alignment)
复制代码
猜一下打印的结果是什么,为什么是这样的结果呢。
汇编分析
enum TestEnum {
case test1(Int, Int, Int)
case test2(Int, Int)
case test3(Int)
case test4
}
var t = TestEnum.test1(1, 2, 3)
t = .test2(1, 2)
t = .test4
复制代码
先设置汇编指令:Debug->Debug Workflow ->选择always show disassembly。我们在var t = TestEnum那一行打一个断点,运行代码。
看汇编代码能明细看出来,TestEnum.test1(1, 2, 3),把1赋值给rip+0x5d01,把2赋值给rip + 0x5cfe,把3赋值给rip+0x5cfb,把0赋值给rip+0x5cfc。
我们这时候,先看下rip寄存器的内存是多少,值是多少。
可以看出rip的内存地址为**0x1000083D8。当然我们用计算机把0x5d01+0x1000026d7,也能算出来是0x1000083D8。**x/4xg ox1000083D8就可以读取值出来,那为什么是都是0呢,是因为我们断点还没走一下,LLDB指令连续4个si,让断点跑到leaq 0x5cdd(%rip), %rdx处。
可以看出来Int类型是8个字节,用8个字节存1,8个字节存2,8个字节存3,movb,b是1个字节,存的是标记位0。
按这种断点形式,继续看t = .test2(1, 2),前面8个字节存1,8个字节存2,标记位是1。
这就是为什么打印出来的实际占用内存为25了,分配的内存为32
print(MemoryLayout<TestEnum>.size)//25
print(MemoryLayout<TestEnum>.stride)//32
print(MemoryLayout<TestEnum>.alignment)//8
复制代码
枚举内存分析结论
对于关联值,我们直接算出来关联值的最大值,如果有多个,就存在标记位1个字节。
对于原始值,rawValue可以获取,是不占用内存枚举变量的内存。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END