汇编文件中的CFI指令

这篇文章CFI directives in assembly file (18 Jan 2017),   是出自google 工程师Adam Langley


   问题提出:

  •      函数调用栈

:                :
| caller's stack | 
+----------------+ <----$rsp value before CALL
| return address |
+----------------+ <----$rsp at function entry
| caller's rbp   | 
+----------------+ <----$rbp always points here
| callee's stack | 

函数调用中 调用call指令时将call指令的下一条指令 return address 入栈, 其中return address存放在RIP寄存器中也就是将 RIP入栈,之后进入子函数后会将父函数的栈基地址入栈,其中父函数的栈基地保存在RBP寄存器中。


  •      函数栈调用框架:

push rbp

mov rbp, rsp

                   …. (子函数处理部分)

mov rsp, rbp

                    pop bp

(leave)

  •      问题在于

1)对于只有少量代码的函数;

         2)  如果使用  -O   -fomit-frame-pointer, 选项 会将省略rbp部分


解决方案:

新增额外的调试表, Call Frame Information (CFI), 汇编指令以          .cfi_开头。

CFA, Canonical Frame Address, 它的值为RSP value before CALL

:                :
|    whatever    | <--- CFA   caller's stack
+----------------+
| Saved RIP      |   
+----------------+
| caller’s RBP   | <--- %rsp == CFA - 16
+----------------+
|                |
+----------------+            callee's local variables


CFI设计上就是存储一个(寄存器,偏移)的键值对。

  •      CFI函数栈调用框架:

 .cfi_startproc

.cfi_def_cfa rsp,8

push rbp

.cfi_def_cfa rsp, 16

mov rbp, rsp

.cfi_def_cfa rbp, 16

….

pop rbp

.cfi_def_cfa rsp, 8

ret

.cfi_endproc

  •      CFI的CIE和FDE

CIE(Common Information Entry)公共条目信息

FDE(Frame Description Entry)函数中的CFI指令

  •       CFI指令优化

更新偏移量,更新寄存器:

.cfi_def_cfa_offset,.cfi_def_cfa_register

使用相对值更新偏移量:

.cfi_adjust_cfa_offset

  •       保存寄存器

指示寄存器保存在堆栈中

                   .cfi_offset

  •       CFI表达式

.cfi_escape

允许用户向展开信息添加任意字节。 可以使用它来添加特定于操作系统的CFI操作码,或者GAS尚不支持的通用CFI操作码。

  •       CFI注册号

Register number x86-64 x86 ARM
0 RAX EAX r0
1 RDX ECX r1
2 RCX EDX r2
3 RBX EBX r3
4 RSI ESP r4
5 RDI EBP r5
6 RBP ESI r6
7 RSP EDI r7
8 R8 r8
9 R9 r9
10 R10 r10
11 R11 r11
12 R12 r12
13 R13 r13
14 R14 r14
15 R15 r15
16 RIP

Be First to Comment

发表回复