我在Linux内核中调试了一个无关紧要的问题,看到由主管管理的etcd进程反复出现页面错误异常并接收到SIGSEGV。
我很好奇并使用objdump反汇编程序,发现错误的amd64指令是:
89 04 25 00 00 00 00 mov %eax,0x0
然后我看了一个hello world程序的反汇编。我在go编译器生成的代码中看到了一个非常常见的模式,即在函数结束时,在ret
之后,sa 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>
这是一些玩法吗?如果是这样,它是如何工作的?我猜0x400c51
它跳转到0x400cac
,触发SIGSEGV
,然后处理,然后下一条指令跳回0x400c53
。
答案 0 :(得分:1)
我从Go开发者那里得到了一些答案:https://groups.google.com/forum/#!topic/golang-nuts/_7yio3ZfVBE
基本上,这种模式是过时实现中的零检查。引用的是Keith Randall的答案。
如果指针为nil,则跳转到生成a的指令 故障。那个错误用于启动nil ptr恐慌。
这是一个非常低效的代码序列。 jmps似乎永远不会出现 用过的。升级到更新的Go版本,您将看到它 改善。