CFI指令意味着什么?(还有一些问题)

Per*_*age 11 c c++ x86 assembly gcc

好的,这将是一个很长的问题.我试图理解"缓冲区溢出"是如何工作的.我正在阅读通过aleph1 粉碎堆栈以获得乐趣和利润,并且刚刚获得了以下代码的反汇编:

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}

void main() {
  function(1,2,3);
}
Run Code Online (Sandbox Code Playgroud)

使用-SGCC旗帜的disameembly 给了我:

    .file   "example1.c"
    .text
    .globl  function
    .type   function, @function
function:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $48, %rsp
    movl    %edi, -36(%rbp)
    movl    %esi, -40(%rbp)
    movl    %edx, -44(%rbp)
    movq    %fs:40, %rax
    movq    %rax, -8(%rbp)
    xorl    %eax, %eax
    movq    -8(%rbp), %rax
    xorq    %fs:40, %rax
    je  .L2
    call    __stack_chk_fail
.L2:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   function, .-function
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $3, %edx
    movl    $2, %esi
    movl    $1, %edi
    call    function
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

这些.cfi指令不在Aleph1的论文中,我猜他们当时没有被使用过.我已经在SO上阅读了这个问题 ,我得到它们被GCC用于异常处理.我还读了关于SO的另一个问题,我得到了.LFB0,.LFE0,.LFE1和.LFB1是标签,但我有以下疑问:

  1. 我知道.cfi指令用于异常处理,但我不明白它们的含义.我一直在这里,我看到一些定义,如:

.cfi_def_cfa寄存器,偏移量

.cfi_def_cfa将计算CFA的规则定义为:从寄存器获取地址并向其添加偏移量.

但是,如果你看一下我上面的反汇编,你找不到任何注册名称(比如EAX,EBX等),而是在那里找到一个数字(我一般都找到'6')而且我不喜欢我不知道那应该是一个寄存器.特别是,任何人都可以解释什么.cfi_def_cfa_offset 16,.cfi_offset 6, -16,.cfi_def_cfa_register 6.cfi_def_cfa 7, 8是什么意思?还有什么CFA意思呢?我问这个是因为主要是在书籍/论文中,程序序言如下:

 pushl %ebp
 movl %esp,%ebp
 subl $20,%esp
Run Code Online (Sandbox Code Playgroud)

但是,现在我认为现代计算机中的程序序列如下:

    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $48, %rsp
Run Code Online (Sandbox Code Playgroud)

最初我认为使用CFI指令而不是sub助记符来设置偏移量,但事实并非如此; sub尽管使用了CFI指令,该命令仍在使用.

  1. 我知道每个程序都有标签.但是,为什么程序中有多个嵌套标签?在我的情况下,main有.LFB1和.LFE2标签.多个标签需要什么?类似地,该function过程具有标签.LFB0,.L2和.LFE0

  2. 两个程序的最后3行似乎用于一些内务处理功能(告诉程序的大小,可能?)但我不确定它们是什么意思.任何人都可以解释他们的意思和用途是什么?

编辑:

(再添一个问题)

  1. CFI指令是否会占用任何空间?因为在过程"函数"中,每个int参数占用4个字节而且它的数量是3,所以所有参数在内存中占用12个字节.接下来,第一个char数组需要8个字节(向上舍入5个字节到8个字节),下一个数组需要12个字节(向上舍入10个字节到12个字节char),因此整个char数组需要20个字节.总结这些,参数和局部变量只需要12 + 20 = 32个字节.

    但是在过程"function"中,编译器减去48个字节来存储值.为什么?

Lin*_*cer 9

CFI代表呼叫帧信息.这是编译器描述函数中发生的事情的方式.调试器可以使用它来呈现调用堆栈,链接器可以合成异常表,进行堆栈深度分析以及其他类似的事情.

实际上,它描述了存储处理器寄存器等资源的位置以及返回地址的位置.

CFA代表调用帧地址,它表示调用者函数的堆栈指针位置的地址.需要这样才能获取有关堆栈中下一帧的信息.


bla*_*abb 7

Lindy Dancer 回答了什么cfi and cfa means( call frame information) 和 ( call frame address)

.L<num>表示按照 Google 在 x64 GCC 中的各种花絮命名的标签,所有标签均以以下格式开头.L 和结尾,标签也是a numeral 如此.L1 , .L2 , .L....infinity

根据谷歌和一些早期的SO答案BF<num>表明 Function-Begin 并EF<num>表明FUNCTION-END

所以.LBF0 , .LBF1 . LBF.....infinity.LFE0 ,......., .LFE....infinity

表示每个函数中的函数开始和函数结束,编译器可能需要它们来处理一些内部需求,因此您此时应该忘记它们,除非非常需要深入了解编译器内部

另一个标签.L2的存在是为了解决函数中的分支指令 je

je  .L2
Run Code Online (Sandbox Code Playgroud)

此外,每个编译器都会将对参数和局部变量的访问对齐并填充到特定边界

我不能确定,但​​ x64 默认对齐是 16 个字节,我认为对于 GCC 所以如果你请求一个奇怪的保留,比如

char foo[ 5 ] 或
BYTE blah [ 10 ]

索引5 and 10甚至没有对齐x86

为 5 x86 compiler will assign 8 字节s and for 10 16 bytes

同样适合x64 gcc might assign 16 bytes您的每个要求

你实际上不应该担心为什么编译器会这样做

当您试图理解汇编逻辑时,只需关注地址

如果编译器决定它will put x at rbp +/- Xalso access it at the same location贯穿该变量的范围或生命周期