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

时间:2014-06-27 23:30:04

标签: c++ c gcc assembly x86

好的,这将是一个很长的问题。我试图理解"缓冲区溢出"作品。我正在阅读aleph1的Smashing the stack for fun and profit,并且刚刚得到了以下代码的反汇编:

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

void main() {
  function(1,2,3);
}

使用GCC -S标志的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

Aleph1的论文中没有.cfi指令,我猜他们当时没有使用它们。我已经阅读了this question on SO,我得知它们被GCC用于异常处理。我也读过another question on SO,我得到了.LFB0,.LFE0,.LFE1和.LFB1是标签,但我有以下疑问:

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

    .cfi_def_cfa register,offset

         

    .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
    

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

        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $48, %rsp
    

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

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

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

    3. 编辑:

      (再增加一个问题)

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

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

3 个答案:

答案 0 :(得分:9)

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

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

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

答案 1 :(得分:2)

根据您在逆向工程中的请求,我将我的评论内容作为答案放在这里(我不知道这是否会继续,因为我看到一个激烈的竞争,在那里向下投票和向上投票)< / p>

Lindy Dancer回答了cfi and cfa meanscall frame information)和(c all frame address

的内容

.L<num>表示Google中x64 GCC名称中各种花絮的标签。以下格式的所有标签均以.L开头,以a numeral结尾,因此.L1 , .L2 , .L....infinity为标签< / p>

根据Google和一些早期的SO个答案BF<num>表示功能开始,EF<num>表示FUNCTION-END

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

表示函数开始,函数在每个函数中结束,编译器可能需要这些函数来处理一些内部需求,所以除非有非常需要深入研究编译器内部,否则你应该忘记它们

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

je  .L2

每个编译器也会对参数和本地的访问权限进行对齐并填充到某个边界

我无法确定,但对于GCC,x64默认对齐是16字节 所以,如果您要求奇怪的预订,如

char foo [ 5 ]或
BYTE blah [ 10 ]

即使对于5 and 10

,索引x86也未对齐

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

与您的每个请求一样明智x64 gcc might assign 16 bytes

你实际上不应该担心为什么编译器能做它所做的事情

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

如果编译器决定will put x at rbp +/- X它将also access it at the same location超出该变量的范围或生命期

答案 2 :(得分:1)

48是跳过参数和本地人。 5字节数组在8字节边界上对齐,10字节在16字节边界上对齐。参数每个需要8个字节,因此参数的3 * 8加上本地的8 + 16给出了24 + 24或48.您可以通过询问每个事件的地址来在gdb中看到它。