inout 从 汇编 验证Swift的 inout 本质

inout 从 汇编 验证Swift的 inout 本质


文章图片

伊努特哲学
我经常想改变自己。
早上上班的路上,晚上下班的公交车
就像这个变化函数一样
功能更改{
数量= 20
}
var年龄= 18岁
打印)//运行错误
永源18
直到有一天,
功能更改{
数量= 20
}
var年龄= 18岁
打印)
// 20
我突然长大了
路人:
我明白,我明白,作者,你想告诉我们,如果你想改变,你必须付出,没有进就没有出
我的嘴渴了
我先煮鸡汤
...
有趣的小便
我的核心思想是
你学得越多,你变老得越快。
不想承认失败,就变成秃头

inout 从 汇编 验证Swift的 inout 本质


文章图片

&地址交付
接下来,让我们看看我做了什么
变化
& symbol,这里表示寻址字符,它采用全局变量age的内存地址
不难猜测,年龄的存储器地址被传递到函数中,并且年龄的存储器地址所指向的值被修改
我们如何证明这一点?
好的,断点落在变更上
1.0x100000ed1 : movq x12,0x1144_dyld_private + 4
2.0x100000edc : movl %edi,-0x1c
-> 3.0x100000edf : movq %rax,%rdi
4.0x100000ee2 : leaq -0x18,%rax
5.0x100000ee6 : movq %rsi,-0x28
6.0x100000eea : movq %rax,%rsi
7.0x100000eed : movl x21,%edx
8.0x 100000 ef 2:callq 0x 100000 f78;swift_beginAccess的符号存根
9.0x100000ef7 : leaq 0x1122,% rdi年龄:Swift.Int
10.0x 100000 EFE:callq 0x 100000 f20;变更-> Swift.Int在主要。斯威夫特:11
第1行:
movq x12,0x1144
将8个字节的Int类型18放入0x1144内存地址0x1144
如前一篇文章所述,该表单表示全局变量的地址值,它应该是变量age的地址值
第2行:
Rip%:指向下一条指令的地址
在第二行设置0x100000edc+0x1144 = 0x100002020
0x100002020是存储器18的存储器地址
第9行:
【inout 从 汇编 验证Swift的 inout 本质】leaq 0x1122,%rdi
将0x1122地址值传递给rdi,rdi表参数,即以地址0x1122为参数,传递到第十行。
这个0x1122可以计算为0x100002020
地址值是18吗
地址值18作为参数传递给了change
第10行:
由于地址值被传递到函数变更中,所以继续深入变更内部
inout`change:
-> 1.0x100000f60 : pushq %rbp
2.0x100000f61 : movq %rsp,%rbp
3.0x100000f64 : movq x0,-0x8
4.0x100000f6c : movq %rdi,-0x8
5.0x100000f70 : movq x14,
6.0x100000f77 : popq %rbp
7.0x100000f78 : retq
第4行:
movq %rdi,-0x8
因为rdi%是18岁的记忆地址,这句话意味着18被放入-0x8
-0x8位于函数更改的堆栈空之间,随后被释放
第5行:
movq x14,
因为此时rdi指向年龄的内存地址,该地址没有改变,所以第五行将立即将20计为rdi
堆栈作为返回值,并将其分配给年龄
因此
年龄变成20岁
总结:
从上面简单的例子来看,应该暂时总结一下
inout的本质确实是引用传递,也就是引用地址传递
类的存储属性转移
定义一个类和存储属性期限,看看存储属性是如何传入传出的。
功能更改{
数量= 20
}
人员类别{
年龄变化:整数
}
风险值=人
->改变
P的字节占用是8字节,指的是栈空之间的8字节作为地址,指向栈空之间的内存分配

推荐阅读