随笔-156  评论-223  文章-30  trackbacks-0
曾因朋友问到监控,致使我探究了kretprobe的实现,想到编译中的尾调用优化,作个小结
​1. kretprobe_trampoline_holder该跳转函数无参是必须的或说最好的通用设计,因为替换返回地址是非正常程序流程,即被探测函数的调用者无感知,不存在为跳转函数准备入参。若要设计传参且只读,则不会破坏被探测函数调用者的上下文,但跳转函数内部流程怎么用参数是个问题,这需要一种约定
​2. 跳转函数为调用trampoline_handler准备入参,即在栈上构造一个(不完整的)pt_regs,再把它地址即栈顶赋给rdi,rdi是x86_64上传入第一参数使用的寄存器,同时预留一个栈单元存放原返回地址(为什么要预留?因为被探测函数返回时,其调用者存放返回地址的栈空间被释放了,所以得在跳转函数内造一个)。由于trampoline_handler内调到用户自定义handler而传入pt_regs,因此自定义handler内要注意最好别改动pt_regs,否则会破坏被探测函数调用者的上下文
​3. 表面看kretprobe的实现流程有点像尾调用优化,但有本质区别。后者中被调尾函数直接释放父调用者的栈帧,就可恢复到父调用者的返回地址;前者不能这样干,因为被探测函数的返回地址被替换了,所以需要一个时地(时机地点)恢复,而这时地正是跳转函数的收尾序列代码,把原来的返回地址放于上述2所讲的预留栈单元,这样最后的ret指令弹出它并跳到原返回地址执行。为保证恢复后正常执行,还得恢复被探测函数调用者的上下文即寄存器信息(无须恢复栈内容,因为上述1讲到了跳转函数是无参的)



posted on 2023-09-13 02:26 春秋十二月 阅读(302) 评论(0)  编辑 收藏 引用 所属分类: System

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理