汇编,CFA,CFI

1)来源

.cfi_def_cfa_offset directives in assembly generated by GCC

不知道intel有没有。

main() is called from somewhere else (in the libc C runtime support code), and, at the time the call instruction is executed, %rsp will point to the top of the stack (which is the lowest address - the stack grows downwards)

CFI(calling frame info)的作用是出现异常时stack回滚(unwind)。而回滚的过程是一级级CFA往上回退,直到异常被catch

.cfi指令解读(一)_Alan的修炼的博客-CSDN博客_cfi_def_cfa_offset

上面这个网址其实讲得挺好的。

CFA定义为执行call xxxSP(stack pointer)所指向的地址。

 
  1. pushl %ebp

  2. .cfi_def_cfa_offset 8

  3. .cfi_offset 5, -8

表示执行完pushl %ebpSPCFA偏了8字节(4字节return address,4字节ebp

 
  1. movl %esp, %ebp

  2. .cfi_def_cfa_register 5

表示执行完movl %esp, %ebpcfa_register不再是esp,而是ebp

 
  1. leave

  2. .cfi_restore 5

  3. .cfi_def_cfa 4, 4

表示执行完leaveebp的值已经恢复到初始状态,并且CFA的计算方式应该是esp+4

其中寄存器对应的数字是架构相关的,详细参考xxx_map_dwarf_register

5d8067c60… Jace*0760 static unsigned x86_64_map_dwarf_register(unsigned regno, const struct module* module, BOOL eh_frame)
e2b62c91d… Eric*0761 {
                0762     unsigned    reg;
                0763 
                0764     if (regno >= 17 && regno <= 24)
                0765         reg = CV_AMD64_XMM0 + regno - 17;
                0766     else if (regno >= 25 && regno <= 32)
                0767         reg = CV_AMD64_XMM8 + regno - 25;
                0768     else if (regno >= 33 && regno <= 40)
                0769         reg = CV_AMD64_ST0 + regno - 33;
                0770     else switch (regno)
                0771     {
                0772     case  0: reg = CV_AMD64_RAX;    break;
                0773     case  1: reg = CV_AMD64_RDX;    break;
                0774     case  2: reg = CV_AMD64_RCX;    break;
                0775     case  3: reg = CV_AMD64_RBX;    break;
                0776     case  4: reg = CV_AMD64_RSI;    break;
                0777     case  5: reg = CV_AMD64_RDI;    break;
                0778     case  6: reg = CV_AMD64_RBP;    break;
                0779     case  7: reg = CV_AMD64_RSP;    break;
                0780     case  8: reg = CV_AMD64_R8;     break;
                0781     case  9: reg = CV_AMD64_R9;     break;
                0782     case 10: reg = CV_AMD64_R10;    break;
                0783     case 11: reg = CV_AMD64_R11;    break;
                0784     case 12: reg = CV_AMD64_R12;    break;
                0785     case 13: reg = CV_AMD64_R13;    break;
                0786     case 14: reg = CV_AMD64_R14;    break;
                0787     case 15: reg = CV_AMD64_R15;    break;
                0788     case 16: reg = CV_AMD64_RIP;    break;
                0789     case 49: reg = CV_AMD64_EFLAGS; break;
                0790     case 50: reg = CV_AMD64_ES;     break;
                0791     case 51: reg = CV_AMD64_CS;     break;
                0792     case 52: reg = CV_AMD64_SS;     break;
                0793     case 53: reg = CV_AMD64_DS;     break;
                0794     case 54: reg = CV_AMD64_FS;     break;
                0795     case 55: reg = CV_AMD64_GS;     break;
                0796     case 62: reg = CV_AMD64_TR;     break;
                0797     case 63: reg = CV_AMD64_LDTR;   break;
                0798     case 64: reg = CV_AMD64_MXCSR;  break;
                0799     case 65: reg = CV_AMD64_CTRL;   break;
                0800     case 66: reg = CV_AMD64_STAT;   break;
                0801 /*
                0802  * 56-57 reserved
                0803  * 58 %fs.base
                0804  * 59 %gs.base
                0805  * 60-61 reserved
                0806  */
                0807     default:
                0808         FIXME("Don't know how to map register %d\n", regno);
                0809         return 0;
                0810     }
                0811     return reg;
                0812 }
                0813 

/wine-7.5/dlls/dbghelp/cpu_x86_64.c

基本上解释清楚了。

7.12.13 .cfi_offset register, offset

Previous value of register is saved at offset offset from CFA.

这里的register是一个编号,真是莫名其妙的规定。

2)

We refer to this address as the Canonical Frame Address or CFA

CFA是个地址,与RSP之间的距离,有什么用?

As the call instruction is executed, it will push a 64-bit (8 byte) return address onto the stack:

:                :
|    whatever    | <--- CFA
+----------------+
| return address | <--- %rsp == CFA - 8
+----------------+

Now we are running the code at main, which executes subq $8, %rsp to reserve another 8 bytes of stack for itself:

:                :
|    whatever    | <--- CFA
+----------------+
| return address |
+----------------+
| reserved space | <--- %rsp == CFA - 16
+----------------+
#include <stdio.h>

int main(int argc, char** argv)
{
        printf("%d", 0);
        return 0;
}

The generated assembly:

        .file   "test.c"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%d"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
.LFB22:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        xorl    %edx, %edx
        movl    $.LC0, %esi
        movl    $1, %edi
        xorl    %eax, %eax
        call    __printf_chk
        xorl    %eax, %eax
        addq    $8, %rsp
        .cfi_def_cfa_offset 8
        ret
            .cfi_endproc
.LFE22:
        .size   main, .-main
        .ident  "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
        .section        .note.GNU-stack,"",@progbits

这个.cfi_def_cfa_offset 是解释得清楚了。

rsp 栈顶,低地址。rbp 栈底,高地址。向下生长。

.cfi_def_cfa_offset modifies a rule for computing CFA. Register remains the same, but offset is new. Note that it is the absolute offset that will be added to a defined register to compute CFA address.

不知道有什么用。

https://sourceware.org/binutils/docs/as/CFI-directives.html#CFI-directives

7.12.11 .cfi_def_cfa_offset offset

.cfi_def_cfa_offset modifies a rule for computing CFA. Register remains the same, but offset is new. Note that it is the absolute offset that will be added to a defined register to compute CFA address.

7.12.13 .cfi_offset register, offset

Previous value of register is saved at offset offset from CFA.

寄存器的前一个值被保存在CFA的偏移地址?什么意思嘛?

3)

8.12. .cfi_def_cfa_offset offset

.cfi_def_cfa_offset modifies a rule for computing CFA. Register remains the same, but offset is new. Note that it is the absolute offset that will be added to a defined register to compute CFA address.

绝对位置,问题是CFA有什么用?

8.14. .cfi_offset register, offset

Previous value of register is saved at offset offset from CFA.

都属于Assembler Directives,编译指导语句。

做啥用的嘛?

8.3. .align abs-expr, abs-expr, abs-expr

Pad the location counter (in the current subsection) to a particular storage boundary. The first expression (which must be absolute) is the alignment required, as described below.

对齐方式,具体是怎么回事嘛?其实要举例子才行。

http://web.mit.edu/rhel-doc/3/rhel-as-en-3/index.html

桢的概念

4)

Pseudo Ops (Using as)

5)

CFI 即 Call Frame Information,是 DWARF 2.0 定义的函数栈信息,DWARF 即 Debugging With Attributed Record Formats ,是一种调试信息格式。

.cfi_ 开头的汇编指示符,例如 .cfi_startproc 、.cfi_undefined 、.cfi_endproc 等,CFI 即 Call Frame Information,是 DWARF 2.0 定义的函数栈信息,DWARF 即 Debugging With Attributed Record Formats ,是一种调试信息格式。 .cfi_ 开头的汇编指示符用来告诉汇编器生成相应的 DWARF 调试信息,主要是和函数有关。.cfi_startproc 定义函数开始,.cfi_endproc 定义函数结束。
意思可以全部删掉?

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值