gcc 在嵌入式软件中一些常见的用法(待补充)

大多数情况,嵌入式软件工程师并不需要知道gcc编译器是工作的,但是随着调试深入,了解gcc在软件中的一些常见的用法大有裨益。

这里列一下遇到的一些嵌入式软件中用到的一些gcc知识。

1 GCC关闭某函数的优化

软件库使用O2/O3优化,有时debug时,需要关闭其中某些函数的优化(即使用此函数使用O0优化),可以采用如下方式:

注意:只能放到函数外,不能放到函数内部。在特定代码前保存当前的编译选项,然后对特定的代码使用O0优化级别,最后再恢复之前保存的编译选项。

示例如下:

#pragma GCC push_options
#pragma GCC optimize("O0")
void conv_test()
{
  ...
}
#pragma GCC pop_options

2 怎么声明某个数组多少字节对齐?

为了效率,CPU从内存取数据并不是一字节一字节去读的,而是一次读取多个字节(如4字节),如果变量地址不对齐(不是4的倍数),则会降低CPU效率。

对齐的含义:
2字节对齐:地址的二进制最后1位为0(2^1)
4字节对齐:地址的二进制最后2位为0(2^2)
8字节对齐:地址的最后3位为0(2^3)
16字节对齐:地址的最后4位为0(2^4)
32字节对齐:地址的最后5位为0(2^5)
64字节对齐:地址的最后6位为0(2^6)

如:声明某个数组16Byte对齐:

 int32_t __attribute__((aligned(16))) a_array[1024];

这样,编译后a_array的地址能被16整除(地址低4bit全为0,2^4 = 16)

3 怎么将某数组定义到外部flash或ram上?

有时数组太大,直接放到片内ram放不下,需要放到外部SDRAM中,可以使用如下方法:

方法1:__ attribute __( at(绝对地址) )

例如:

const uint8_t bigArray[] __attribute__((at(0x30000000))); 

注意:有可能 GNU GCC 不再支持at方法,方法1不行时,请采用方法2。

方法2:__ attribute __((section(“块名”)))

这种方法稍显麻烦,需要修改链接脚本。

例如:

修改C代码

const uint8_t bigArray[] __attribute__((section(".bigArray"))); 

// 也可以同时设置段于对齐方式
const uint8_t bigArray[] __attribute__((section(".bigArray"))) __attribute__((aligned(64)));

修改lds链接文件,假设外部SDRAM起始地址0x30000000,大小为30MB

/* Program Entry, set to mark it as "used" and avoid gc */
MEMORY
{
    ROM (rx) : ORIGIN =0x08000000,LENGTH =128k
    RAM (rw) : ORIGIN =0x20000000,LENGTH =512k
    EXTSDRAM (rw) : ORIGIN =0x30000000,LENGTH =32M  /* 新增 */
}

/* 在SECTIONS里新增段,段名要与C代码中的字段一致 */

    .bigArray (NOLOAD) : ALIGN(4)
    {
        . = ALIGN(4);
        *(.bigArray)
            *(.bigArray.*)
            . = ALIGN(4);
        __bigArray_free__ = .;
    } > EXTSDRAM

4 GCC关闭函数的自动内敛

如函数:

static void foo() {}

希望编译时不要内涵这个函数,可以改为如下写法:

void __attribute__ ((noinline)) foo() 
{
  ...
}

参考:

  1. 【管中窥豹集】听到“对齐”这两个字你能想到什么?

  2. 来了解一下GNU C __attribute__机制

  3. C语言再学习24——attribute (at())地址定位

  4. RTthread_Studio IDE怎么将数组定义到外部SDRAM中

posted @ 2023-12-01 18:03  sureZ_ok  阅读(73)  评论(0编辑  收藏  举报