英文:
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 <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>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论