0%

GCC 实用方法

GCC 的一些实用的方法。

到底使用了哪个头文件?

一个 SDK 中可能存在多个同名的 .h 文件,如何确定 .c 中到底使用的是哪个 .h 呢?

GCC 有一个选项 -M 可以输出 .c 所包含的所有 .h,使用此方法能确定 .c 使用的 .h 文件。

开发 5062 时遇到了编译错误:error: 'errno' undeclared,可能是 .c 使用了一个错误的非系统的 errno.h,于是到 build 目录下去查找对应的 .d 文件,发现果然用的是一个原厂自己写的 errno.h,其中没有声明 errno。

屏蔽编译 warning 输出

有时候 warning 太多,淹没了 error,可以用 -w 选项屏蔽 warning 输出。

使用 strip 精简静态库的大小

arm-none-eabi-strip -o lib.strip.a lib.a --strip-debug

静态库只能使用--strip-debug选项,去除库中的 debug 信息,可以把一个 16M 的静态库精简到 280K。

注意:使用ar -M < script方式将多个 .a 打包成的静态库不能使用 strip 命令。

在 map 表内查找静态变量和函数地址

静态变量和函数其实在 map 表内也能查到的,首先要使能 GCC 的编译选项-fdata-sections -ffunction-sections,为变量和函数生成一个专有的段名称。

以静态变量来举例说明:

ota.c

1
2
3
4
5
6
static uint8_t flash_data_buf;

void ota(void)
{
...
}

main.c

1
2
3
4
5
6
7
8
9
10
11
void hal_init(void)
{
static uint8_t flash_data_buf;
...
}

void main(void)
{
static uint8_t flash_data_buf;
...
}

对于在函数外的静态变量,在 map 表中形式如下:

1
2
.bss.flash_data_buf
0x0000000000400234 0x1000 build/src/system/ota.o

对于函数内的静态变量,在 map 表中形式如下:

1
2
3
4
.bss.flash_data_buf.5993
0x00000000004001fd 0x1 build/src/system/main.o
.bss.flash_data_buf.5989
0x00000000004001fe 0x1 build/src/system/main.o

这种情况就要结合反汇编来确定了。

__builtin_return_address() 获取调用者的地址

void * __builtin_return_address (unsigned int level)是 GCC 的一个内建函数,__builtin_return_address(0)的含义是,得到当前函数返回地址,即此函数被别的函数调用,然后此函数执行完毕返回后的下一条地址。

1
printf("%s(0) = %p\r\n", __FUNCTION__, __builtin_return_address(0));

反汇编如下:

1
2
3
4
5
6
7
8
...
8088088: 4674 mov r4, lr
...
80880b8: 4622 mov r2, r4
80880ba: 490f ldr r1, [pc, #60] ; (80880f8 <application_start+0x78>)
80880bc: 480f ldr r0, [pc, #60] ; (80880fc <application_start+0x7c>)
80880be: f00b fd67 bl 8093b90 <iprintf>
...

所以这个函数其实就是返回 LR 的值。

AR

http://sourceware.org/binutils/docs-2.31/binutils/ar-cmdline.html#ar-cmdline

ar -rcs archive objects将 objects 文件打包成库

c - create,创建新库

r - replace,替换已有库中的目标文件

s - 更新库中的索引

d - delete,删除库中的目标文件

x - extract,解压出库中的目标文件

t - 列出库中所有的目标文件

坚持原创技术分享,您的支持将鼓励我继续创作!