gpt4 book ai didi

c - c函数的汇编代码

转载 作者:太空狗 更新时间:2023-10-29 14:57:35 26 4
gpt4 key购买 nike

我正在尝试理解 C 函数的汇编代码。我不明白为什么 andl -16 是在 main 完成的。是不是为局部变量分配空间。如果是这样,为什么 subl 32 是为 main 完成的。

我无法理解 func1 的反汇编。对于 8086 处理器,随着读取,堆栈从高位地址增长到低位地址。那么这里为什么访问是在 ebp 的正面(用于参数偏移),为什么不在 ebp 的负面。 func1 内部的局部变量是 3 + 返回地址 + 保存的寄存器 - 所以它必须是 20,但为什么是 24? (subl $24,esp)

#include<stdio.h>
int add(int a, int b){
int res = 0;
res = a + b;
return res;
}
int func1(int a){
int s1,s2,s3;
s1 = add(a,a);
s2 = add(s1,a);
s3 = add(s1,s2);
return s3;
}
int main(){
int a,b;
a = 1;b = 2;
b = func1(a);
printf("\n a : %d b : %d \n",a,b);
return 0;
}

汇编代码:

       .file   "sample.c"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
leave
ret
.size add, .-add
.globl func1
.type func1, @function
func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -4(%ebp)
movl 8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl -4(%ebp), %eax
movl %eax, (%esp)
call add
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size func1, .-func1
.section .rodata
.LC0:
.string "\n a : %d b : %d \n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $1, 28(%esp)
movl $2, 24(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call func1
movl %eax, 24(%esp)
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 8(%esp)
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits

最佳答案

andl $-16, %esp 通过清除低四位将堆栈指针对齐到 16 字节的倍数。

(%ebp) 唯一使用正偏移的地方是参数访问。

您没有说明您的目标平台是什么或者您使用什么开关进行编译。汇编代码显示一些 Ubuntu 标识符已被插入,但我不熟悉它使用的 ABI,除此之外它可能类似于通常用于 Intel x86 架构的 ABI。所以我猜测 ABI 在例程调用时需要 8 字节对齐,因此编译器将 func1 的堆栈帧设为 24 字节而不是 20 字节,以便保持 8 字节对齐。

我会进一步猜测编译器将堆栈对齐到 main 开头的 16 字节作为编译器中的一种“偏好”,以防它使用偏好 16 字节的 SSE 指令对齐,或其他喜欢 16 字节对齐的操作。

所以,我们有:

main 中,andl $-16, %esp 将堆栈对齐为 16 字节的倍数作为编译器偏好。在 main 中,28(%esp)24(%esp) 引用编译器保存在堆栈中的临时值,而 8(%esp)4(%esp)(%esp)用于传递参数给func1打印。我们从汇编代码调用 printf 但它在您的代码中被注释掉的事实中看到,您粘贴的 C 源代码与用于生成汇编代码的 C 源代码不同: 这是不是从 C 源代码生成的正确汇编代码。

func1 中,堆栈上分配了 24 个字节而不是 20 个字节以保持 8 字节对齐。在 func1 中,参数通过 8(%ebp)4(%ebp) 访问。从 -12(%ebp)-4(%ebp) 的位置用于保存变量的值。 4(%esp)(%esp) 用于向add 传递参数。

这里是func1的栈帧:

    - 4(%ebp) = 20(%esp): s1.    - 8(%ebp) = 16(%esp): s2.    -12(%ebp) = 12(%esp): s3.    -16(%ebp) =  8(%esp): Unused padding.    -20(%ebp) =  4(%esp): Passes second parameter of add.    -24(%ebp) =  0(%esp): Passes first parameter of add.

关于c - c函数的汇编代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15753646/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com