【发布时间】:2015-06-14 04:14:45
【问题描述】:
[汇编代码]
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
movl $5, 20(%esp)
movl $3, 24(%esp)
movl 24(%esp), %eax
movl %eax, 4(%esp)
movl 20(%esp), %eax
movl %eax, (%esp)
call add
movl %eax, 28(%esp)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.globl add
.type add, @function
add:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $16, %esp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
addl %edx, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
[源代码]
int add(int k, int l);
int main(int argc, char **argv) {
int a, b, ret;
a = 5;
b = 3;
ret = add(a, b);
return 0;
}
int add(int k, int l) {
int x;
x = k + l;
return x;
}
我正在研究汇编语言级别的 c 函数的调用约定。
如您所知,.cfi 用于添加调试信息。我已经阅读了一些 cfi 文章并知道每个指令的含义。
在上述汇编代码中,.cfi_def_cfa_offset 8 和 .cfi_offset 5 -8 指令连续出现。这发生在“main”函数和“add”函数中。
但是,我不知道为什么会这样。我所知道的是.cfi_def_cfa_offset 和.cfi_offset 用于制作保留内存来存储调试信息。在此代码中,该偏移量首先设置为 +8,然后设置为 -8。结果是……没有剩余的内存空间来存储 cfi。我说的对吗?
我认为堆栈段是这样工作的。
.cfi_startproc
|-------------|
| whatever | <- %esp = CFA ↑ increase address
|-------------|
| | ↓ stack grow
|_____________|
.pushl %ebp
|-------------|
| whatever |
|-------------|
| %ebp | <- %esp
|_____________|
.cfi_def_cfa_offset 8
|-------------|
| whatever | <- %esp
|-------------|
| whatever |
|-------------|
| %ebp |
|-------------|
.cfi_offset 5 -8
|-------------|
| whatever |
|-------------|
| whatever |
|-------------|
| %ebp | <- %esp
|-------------|
subl $32, %esp
|-------------|
| whatever |
|-------------|
| %ebp |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| | <- %esp
|-------------|
movl $5, 20(%esp)
|-------------|
| whatever |
|-------------|
| %ebp |
|-------------|
| |
|-------------|
| |
|-------------|
| 5 |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| |
|-------------|
| | <- %esp
|-------------|
等等……
问题 2。
在过程add,调用函数的参数被移动到被调用函数寄存器。
movl 12(%ebp), %eax
movl 8(%ebp), %edx
但是,在我的计算中,8(%ebp) 并没有指向调用者堆栈的顶部。因为,
1) 在pushl %ebp,%esp 减去 4
2) 在cfi_offset 5, -8,%esp 是 sbracted 8(这样,我忽略了.cfi_def_cfa_offset 8。我不确定)
所以,这样调用函数栈顶应该是12(%ebp),而8(%ebp)是指向存储的调用函数的基指针。
我不知道我不知道...我需要你的帮助。
-添加
What do the CFI directives mean? (and some more questions)
这个 SO 问题与我几乎相似。但没有人清楚地回答这个问题。
【问题讨论】:
-
没有什么叫做“c 程序集”
-
@LưuVĩnhPhúc 这对我来说不是有用的问题。而不是stackoverflow.com/questions/24462106/… 对我更有帮助。