go编译器生成的汇编代码中的这种模式是什么?

Wei*_* Hu 7 assembly go

我在Linux内核中调试了一个无关紧要的问题,看到由主管管理的etcd进程反复出现页面错误异常并接收到SIGSEGV.

我好奇并使用objdump来反汇编程序,并发现错误的amd64指令是:

89 04 25 00 00 00 00    mov    %eax,0x0
Run Code Online (Sandbox Code Playgroud)

然后我看了一个hello world程序的反汇编.我在go编译器生成的代码中看到了一个非常常见的模式,即在函数结束时ret,mov紧接着,然后jmp返回函数.例如,

0000000000400c00 <main.main>:
  400c00:       64 48 8b 0c 25 f0 ff    mov    %fs:0xfffffffffffffff0,%rcx
  400c07:       ff ff
        ...
  400c4b:       48 83 7c 24 48 00       cmpq   $0x0,0x48(%rsp)
  400c51:       74 59                   je     400cac <main.main+0xac>
  400c53:       48 c7 04 24 c0 fc 47    movq   $0x47fcc0,(%rsp)
  400c5a:       00

        ...
  400cab:       c3                      retq
  400cac:       89 04 25 00 00 00 00    mov    %eax,0x0
  400cb3:       eb 9e                   jmp    400c53 <main.main+0x53>
Run Code Online (Sandbox Code Playgroud)

这是一些玩法吗?如果是这样,它是如何工作的?我猜0x400c51它跳转到0x400cac,触发a SIGSEGV,处理然后下一条指令跳回0x400c53.

Wei*_* Hu 1

我从 Go 开发者那里得到了一些答案: https://groups.google.com/forum/#! topic/golang-nuts/_7yio3ZfVBE

基本上,这种模式是过时实现中的 nil 检查。引用的是 Keith Randall 的回答。

如果指针为零,则跳转到产生错误的指令。该错误用于启动 nil ptr 恐慌。

这是一个非常低效的代码序列。jmp 似乎从未被使用过。升级到最新的 Go 版本,您会发现它已得到改进。