提问人:DocDriven 提问时间:11/8/2023 更新时间:11/8/2023 访问量:95
如何解释英特尔 x86 汇编的特殊性?
How to interpret particularities of Intel x86 assembly?
问:
考虑以下简单的 C 代码:
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int var = 6;
int var2 = 5;
int var3 = add(var, var2);
return 0;
}
编译此代码将生成以下汇编代码:gcc core.c -O0 -g
.file "core.c"
.text
.globl add
.type add, @function
add:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %edx
movl -8(%rbp), %eax
addl %edx, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size add, .-add
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $6, -12(%rbp)
movl $5, -8(%rbp)
movl -8(%rbp), %edx
movl -12(%rbp), %eax
movl %edx, %esi
movl %eax, %edi
call add
movl %eax, -4(%rbp)
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
在 gdb 中,我在输入 add 函数时设置了一个断点。看一下此时内存中的堆栈(和):$rbp = 0x7fffffffdb10
$rsp = 0x7fffffffdb10
0x7fffffffdb50: 0xffffdc30 0x00000001 0xffffdc48 0x00007fff
0x7fffffffdb40: 0x00000000 0x00000000 0x55555141 0x00005555
0x7fffffffdb30: 0x00000001 0x00000000 0xf7c29d90 0x00007fff frame ptr, main RA
0x7fffffffdb20: 0x00001000 0x00000006 0x00000005 0x00005555 4096, var, var2, var3
rbp --> 0x7fffffffdb10: 0xffffdb30 0x00007fff 0x5555516a 0x00005555 main frame, add RA
0x7fffffffdb00: 0x00000002 0x00000000 0x00000005 0x00000006 (8 rand byte), var2, var
我们可以看到几件事:
- 当前基指针 (RBP) 指向主帧地址。
- 上面是 main 函数的返回地址 (0x55555555516a)。
- 按照这个逻辑,主帧的基指针(0x...db30) 指向 0x1,返回地址为 0x7ffff7c29d90。
- 由于 main 有 3 个局部变量,它保留了 16 个字节 (0x...db20 到 0x...db2c),并将它们以相反的顺序放在那里。
- Add 函数在不移动堆栈指针的情况下推送堆栈上计算所需的值 (0x...db08 和 0x...db0c)。
对于问题:
Q1:返回地址和底架的值是否在主特殊值中?至少 RA 不能是恒定的,因为不能保证它是免费的。
问题 2:为局部变量分配内存时,为什么分配 16 个字节而不是预期的 12 个字节?(怀疑对齐?额外字节中的0x1000是什么意思?
Q3:add计算结果时,为什么堆栈指针在堆栈上明确放置数据时不调整?这难道不会导致信息丢失吗?
我将不胜感激任何帮助,也非常感谢资源指针。
答: 暂无答案
评论
main
0x1000
add
add
leal (%rdi,%rsi), %eax; ret