c++ goto & label 机制汇编探索
文章目录
本文将从汇编的层面来探索 goto 机制,提起 goto 可能会引起程序员的恐惧,但面对恐惧才能战胜恐惧,以致可以利用未曾尝试的点。
arm gcc 实测
|
|
- 使用 gcc -E 即只走预处理看看:
|
|
- 使用 gcc -S 即走到编译这一步看看:
|
|
可以看到 goto 的 label 变成了汇编里的 label (.L4),大体逻辑一致。
解释一下 “\n” 去哪了:正是指令当中的 #10,用 ASCII 码可查出对应的是换行符
0000 1010 | 10 | 0A | LF | ␊ | 换行键 |
---|
- 使用 gcc -c 即走到汇编(这里指的是动作,是把汇编文件进行汇编解释)这一步看看:
|
|
由于已经是二进制的形式了,所以用的是反汇编来看。这里文件格式是 MachO 格式,是苹果所用的,不同平台可能会有些许不同。
同样也是通过 loc_8 这个汇编的 label 来实现,但这个 label 在二进制中长什么样呢?
先看下 b 汇编指令的模样:
然后在二进制里找 __TEXT,__text
段里的这条指令,在 arm 上是 4 个字节一条指令,注意不是在上面代码的 0x14 来找,因为反汇编显示的是相对于 __TEXT,__text
段的偏移,MachO 文件前面还有一大堆记录文件属性的东西。
|
|
由此可得:汇编的 label 其实就是基于 PC 偏移寻址。当然不同平台可能不一样,x86 里绝对寻址也是可行的。
一点没用的性能的分析:b 指令的偏移范围为 +/-128MB
,跳转体最好不要写超过这个范围(虽然应该不会有人写这么大范围的),即 128*1024*1024 / 4
条指令数,超出则会增加指令辅助跳转。
NOTE
没必要过分妖魔化 goto,在本文的例子中,汇编指令与下面这种写法是一样的:
|
|
在 linux、cpython 等源码中都可以看到 goto 的身影。
另外提示一个用法:
goto 不能跨越函数来写,只能跳转到自己函数内的 label。
在 C 中可以使用 setjmp 和 longjmp 来跨函数跳转。
文章作者 calssion
上次更新 2021-05-03