嵌入式技术论坛
直播中

熊本熊

8年用户 1399经验值
擅长:处理器/DSP
私信 关注
[问答]

关于arm-none-eabi-gcc v10.3.1函数和栈调用的问题

编译器为 arm-none-eabi-gcc v10.3.1,优化等级为 -O0
示例代码如下
rt_thread_t s_test_thread = NULL;
void test_func(void)
{
char array[10] = {0};
array[1] = 1;
array[9] = 9;
uint32_t num = 10;
char buf[32] = {0};
buf[15] = 15;
buf[31] = 31;
}
void test_func2(void)
{
char array[10] = {0};
}
void test_func3(void)
{
char array[200] = {0};
}
void test_thread(void *args)
{
test_func();
test_func2();
test_func3();
while (1) {
sleep(1);
}
}
int main(void)
{
s_test_thread = rt_thread_create("test",
test_thread,
NULL,
4 * 1024,
15,
10);
rt_thread_startup(s_test_thread);
while (1) {
sleep(1);
}
return 0;
}
反汇编代码如下
void test_func(void)
{
8000b80: b480 push {r7}
8000b82: b08d sub sp, #52 ; 0x34
8000b84: af00 add r7, sp, #0
char array[10] = {0};
8000b86: 2300 movs r3, #0
8000b88: 623b str r3, [r7, #32]
8000b8a: f107 0324 add.w r3, r7, #36 ; 0x24
8000b8e: 2200 movs r2, #0
8000b90: 601a str r2, [r3, #0]
8000b92: 809a strh r2, [r3, #4]
array[1] = 1;
8000b94: 2301 movs r3, #1
8000b96: f887 3021 strb.w r3, [r7, #33] ; 0x21
array[9] = 9;
8000b9a: 2309 movs r3, #9
8000b9c: f887 3029 strb.w r3, [r7, #41] ; 0x29
uint32_t num = 10;
8000ba0: 230a movs r3, #10
8000ba2: 62fb str r3, [r7, #44] ; 0x2c
char buf[32] = {0};
8000ba4: 2300 movs r3, #0
8000ba6: 603b str r3, [r7, #0]
8000ba8: 1d3b adds r3, r7, #4
8000baa: 2200 movs r2, #0
8000bac: 601a str r2, [r3, #0]
8000bae: 605a str r2, [r3, #4]
8000bb0: 609a str r2, [r3, #8]
8000bb2: 60da str r2, [r3, #12]
8000bb4: 611a str r2, [r3, #16]
8000bb6: 615a str r2, [r3, #20]
8000bb8: 619a str r2, [r3, #24]
buf[15] = 15;
8000bba: 230f movs r3, #15
8000bbc: 73fb strb r3, [r7, #15]
buf[31] = 31;
8000bbe: 231f movs r3, #31
8000bc0: 77fb strb r3, [r7, #31]
}
8000bc2: bf00 nop
8000bc4: 3734 adds r7, #52 ; 0x34
8000bc6: 46bd mov sp, r7
8000bc8: bc80 pop {r7}
8000bca: 4770 bx lr
void test_func2(void)
{
8000bcc: b480 push {r7}
8000bce: b085 sub sp, #20
8000bd0: af00 add r7, sp, #0
char array[10] = {0};
8000bd2: 2300 movs r3, #0
8000bd4: 607b str r3, [r7, #4]
8000bd6: f107 0308 add.w r3, r7, #8
8000bda: 2200 movs r2, #0
8000bdc: 601a str r2, [r3, #0]
8000bde: 809a strh r2, [r3, #4]
}
8000be0: bf00 nop
8000be2: 3714 adds r7, #20
8000be4: 46bd mov sp, r7
8000be6: bc80 pop {r7}
8000be8: 4770 bx lr
void test_func3(void)
{
8000bea: b580 push {r7, lr}
8000bec: b0b2 sub sp, #200 ; 0xc8
8000bee: af00 add r7, sp, #0
char array[200] = {0};
8000bf0: 2300 movs r3, #0
8000bf2: 603b str r3, [r7, #0]
8000bf4: 1d3b adds r3, r7, #4
8000bf6: 22c4 movs r2, #196 ; 0xc4
8000bf8: 2100 movs r1, #0
8000bfa: 4618 mov r0, r3
8000bfc: f03b fd82 bl 803c704
}
8000c00: bf00 nop
8000c02: 37c8 adds r7, #200 ; 0xc8
8000c04: 46bd mov sp, r7
8000c06: bd80 pop {r7, pc}
疑问:

在 test_func 函数中,用到的栈空间为 46(10 + 4 + 32)字节,却预留 52 字节的空间,这多出来的 6 字节的用途是什么?
在 test_func2 函数中,用到的栈空间为 10 字节,却预留 20 字节的空间,这多出来的 10 字节的用途是什么?
在 test_func3 函数中,用到的栈空间为 200 字节,预留 200 字节的空间,刚刚好,和上面的两个函数不一样,这是为什么呢?

回帖(2)

王银喜

2023-8-20 16:58:34
不同类型变量在一块会有对齐和填充
因有可能有浮点运算的原因,arm的函数栈要求8字节对齐
例如test_func2里面其实有对push/pop,+20=24
更多的信息的内部行为,可能就得去研究gcc源码,以及生成的中间产物来理解了。
举报

study875

2023-10-10 10:12:01
在上面的示例代码中,主要问题是函数调用和栈的使用。由于优化等级为-O0,编译器不会进行任何优化,因此会按照C语言的规范生成汇编代码。

首先,当调用test_func时,会创建一个新的栈帧。这个栈帧包括函数参数和局部变量。由于函数中有char类型的数组,每个元素占用1个字节,加上其他变量,栈帧大小不会太大。但是,在调用test_func2和test_func3时,同样会创建新的栈帧,并使用更多的栈空间。

由于在ARM架构中,栈空间是从高地址向低地址增长的,因此如果栈空间不足,就会发生栈溢出。在这种情况下,有两种解决方法:

1. 减少本地变量的数量:在例子中,可以通过减少数组的大小或从函数中删除其他变量来减少栈帧大小。

2. 增加栈的大小:可以通过在链接器脚本中修改栈的大小,或者在编译时使用命令行选项来增加栈的大小。

总之,在编写ARM嵌入式代码时,需要注意函数调用和栈的使用,以避免栈溢出和其他问题。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分