CFI指令是什么意思?(还有一些问题)
What do the CFI directives mean? (and some more questions)
好的,这将是一个很长的问题。我试图了解"缓冲区溢出"是如何工作的。我正在阅读alph1的Smashing the stack,以获得乐趣和收益,并且刚刚获得了以下代码的反汇编:
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
使用GCC的-S
标志的反汇编给我:
.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
.cfi
指令不在Aleph1的论文中,我猜当时没有使用它们。我在SO上读过这个问题,我得到它们被GCC用于异常处理。我还阅读了关于SO的另一个问题,我得到。lfb0,。lfe0,。lfe1和。lfb1是标签,但我有以下疑问:
- 我得到。cfi指令用于异常处理,但我不明白他们的意思。我一直在这里,我看到一些定义,如:
。Cfi_def_cfa寄存器,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
命令仍然被使用。
我知道每个程序都有标签。然而,为什么在一个过程中有多个嵌套的标签?在我的情况下,main有。lfb1和。lfe2标签。为什么需要多个标签?类似地,
function
过程也有标签。lfb0,。l2和。lfe0两个过程的最后3行似乎用于一些内务功能(告诉过程的大小,也许?),但我不确定它们是什么意思。有人能解释一下它们的意思和用途吗?
编辑:CFI指令占用空间吗?因为在过程"function"中,每个int参数占用4个字节,它的个数是3,所以所有参数占用12个字节的内存。接下来,第一个
char
数组占用8字节(将5字节四舍五入到8字节),下一个char
数组占用12字节(将10字节四舍五入到12字节),因此整个char
数组占用20字节。参数变量和局部变量加起来只需要12+20=32字节。但是在过程"function"中,编译器减去48个字节来存储值。为什么?
(再加一个问题)
CFI代表呼叫帧信息。它是编译器描述函数中发生的事情的方式。它可以被调试器用来显示调用堆栈,被链接器用来合成异常表,用于堆栈深度分析和其他类似的事情。
实际上,它描述了诸如处理器寄存器之类的资源存储在何处以及返回地址在何处。
CFA代表调用帧地址,它表示调用函数的堆栈指针位置的地址。
Lindy Dancer回答什么是cfi and cfa means
(call frame information
)和(call frame address
)
.L<num>
表示标签,在x64 GCC名称中,所有以下格式的标签以.L
开始,以a numeral
结束,因此.L1 , .L2 , .L....infinity
是标签
根据Google和一些早期的SO
答案BF<num>
表示Function-Begin, EF<num>
表示FUNCTION-END
so .LBF0 , .LBF1 . LBF.....infinity
and .LFE0 ,......., .LFE....infinity
表示每个函数的函数开始和函数结束,编译器可能需要处理一些内部需求,所以你现在应该忘记它们,除非非常需要深入研究编译器的内部
另一个标签.L2
的存在是为了处理函数
je .L2
每个编译器都将对参数和局部变量的访问对齐并填充到一定的边界
我不能确定,但x64默认对齐是16字节,我认为GCC所以如果你请求一个奇怪的预订,比如
char foo[5] or
BYTE blah [10]
索引5 and 10
不对齐,即使x86
for 5 x86 compiler will assign
8 byte s and for 10 16 bytes
like wise x64 gcc might assign 16 bytes
for your每个请求
实际上你不应该担心为什么编译器做它所做的
当你试图理解汇编的逻辑时,只关注地址
如果编译器决定它是will put x at rbp +/- X
,它将在该变量的作用域或生命周期内also access it at the same location
48是跳过参数和局部变量。5字节数组在8字节边界上对齐,10字节数组在16字节边界上对齐。每个参数占用8字节,所以3*8(参数)加上8 + 16(局部变量)得到24+24或48。您可以在gdb中通过请求这些东西的地址来看到它
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++中的移动分配出现问题.非法指令: 4.
- 在Visual "Microsoft studio 2019"上设置OpenCV 4.1.1时遇到问题?(非法指令。
- 如何使用Qi :: Hold []解析器指令.(带有boost ::交换的属性类型的问题)
- C++:int数组[a][b][C]={0};未将所有值设置为0.是那个指令错了,还是我的输出函数出了问题
- 移植一些代码到GCC,有一些问题与#pragma指令
- CFI指令是什么意思?(还有一些问题)