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

huangapple go评论82阅读模式
英文:

What's this pattern in the assembly code generated by go compiler?

问题

我正在调试Linux内核中一个无关紧要的问题,看到由supervisor管理的etcd进程一直出现页面错误异常并接收到SIGSEGV信号。

我感到好奇,使用objdump反汇编程序,并发现故障的amd64指令是:

89 04 25 00 00 00 00    mov    %eax,0x0

然后我查看了一个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>

这是Go语言玩的一些技巧吗?如果是的话,它是如何工作的?我猜在0x400c51处跳转到0x400cac,触发了SIGSEGV,然后下一条指令跳回到0x400c53

英文:

I was debugging an irrelevant issue in the Linux kernel and saw the etcd process, which was managed by supervisor, was repeatedly hitting page fault exception and receiving SIGSEGV.

I got curious and used objdump to disassemble the program, and found the faulting amd64 instruction to be:

89 04 25 00 00 00 00    mov    %eax,0x0

I then looked at the disassembly of a hello world program. I saw a very common pattern in code generated by go compiler, that is at the end of a function, right after ret, there's a mov followed by a jmp back into the function. For example,

0000000000400c00 &lt;main.main&gt;:
  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 &lt;main.main+0xac&gt;
  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 &lt;main.main+0x53&gt;

Is this some trick played by go? If so, how does it work? I'm guessing at 0x400c51 it jumps to 0x400cac, triggers a SIGSEGV, which is handled and then the next instruction jumps back to 0x400c53.

答案1

得分: 1

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

基本上,这个模式是在过时的实现中进行nil检查。以下是Keith Randall的回答。

如果指针为nil,它会跳转到一个生成错误的指令。这个错误用于触发一个nil指针恐慌。

这是一个相当低效的代码序列。jmps似乎从未被使用过。升级到更高版本的Go,你会看到它已经得到了改进。

英文:

I got some answers from the Go developers: https://groups.google.com/forum/#!topic/golang-nuts/_7yio3ZfVBE

Basically, this pattern is the nil check in the obsolete implementation. Quoted is the answer from Keith Randall.

> If the pointer is nil, it jumps to an instruction that generates a
> fault. That fault is used to start a nil ptr panic.
>
> It's a pretty inefficient code sequence. The jmps never appear to be
> used. Upgrade to a more recent Go version and you'll see it has been
> improved.

huangapple
  • 本文由 发表于 2016年3月17日 15:25:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/36054017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定