2.5 使用编译器
本节展示如何使用KF32工具链从C/C++源文件构建可执行文件。
2.5.1 示例代码
示例中使用的源代码是一个单独的C源文件hello.c:
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
2.5.2 构建可执行文件
对于简单程序,可以使用单个命令将源代码文件编译为可执行文件。
kf32clang --target=kf32r -march=kf32r -T kf32demo.ld hello.c -o hello.elf
该命令会创建一个名为hello.elf的可执行文件。
2.5.3 属性支持
属性用于向编译器提供关于变量、函数、类型或语句的额外信息,以控制其编译行为、优化或内存布局。
通过属性扩展变量或函数的意义,如中断函数。格式为 __attribute__((attribute-list)) 其支持多个属性,属性之间用“,”间隔。
也支持该格式单个属性同格式的多次书写表达多属性。
Interrupt 中断函数
用作中断处理程序的函数生成序言和尾声代码。如:使用 __attribute__((interrupt)) 修饰函数,则该函数即被编译器视为中断函数处理。针对中断向量表入口函数,其为必须声明的属性。
section (“name”) 指定类型段
将函数或变量放入由“name”指定的段。
例如:
void __attribute__((section(".new_sect1"))) foo()
{
return;
}
函数foo将被放入.new_sect1段。
unsigned int var __attribute__((section(".new_sect2")));
变量var将被放入.new_sect2段。
当声明该属性后-ffunction-sections、-fdata-sections命令行选项对该属性定义的函数不起作用。
常见的段定义为 .text(flash空间) | .data(RAM空间) | .bss(RAM空间)。同时根据需要将空间进行顺序使用。针对flash空间,先存放text段的vector文件中代码,即中断向量表;紧接着存放默认的函数代码段.text;跟随存放常量属性的.rdata(readonly flash空间)和.rodata(readonly flash空间)代码信息;工具控制将ram的初始化值跟随结尾存放。针对ram空间,设计ram函数的存放的定义.indata段名,定义初始化的数据.data段名,定义无初始化的数据COMMON或bss段名,RAM的空间默认设计顺序:.indata .data .bss .comm,剩余空间为堆栈空间。
packed 对齐
具有该属性的变量或结构成员将具有所可能的最小对齐值。即,将不为声明分配任何对齐填充存储空间。与aligned属性联合使用时,packed 可以用于设置任意的对齐限制,即大于或小于变量或结构成员的类型所具有的默认对齐值。
需要注意的是,即使声明了该对齐模式,但针对结构体、联合体,其起始仍将按照对齐存放。
如:
struct name1 {
char order1;
struct name2 {
char order2;
} __attribute__((packed)) names;
} __attribute__((packed)) name; // 其order2偏移地址是4。
注:对齐通常控制不同数据类型的联合。同时应考虑芯片对齐属性的要求进行数据类型的合理使用。如连续char数据的操作不应通过int型的指针操作。
注:针对结构体下的位定义,应该使用packed修饰该结构体,否则其代码联合优化将错误的选用对齐的指令操作,从而编译结果与代码期望不符。
常见属性
变量属性支持:
aligned(alignment)定义数据地址对齐配置unused定义参数未使用的不给予警告used即使看起来未使用,也对其进行编译packed一般用于结构体或联合体,明确内部连续地址分配。section("section-name")
函数属性支持:
section("section-name")interrupt定义该函数为中断服务函数,中断函数必须用该属性修饰noinline强制函数不内联,定义的inline及默认由编译器确定是否内联always_inline强制函数内联weak常定义中断函数,即使未发现调用关系仍保留该函数,但地址值为0。alias("fun-name")函数为别名,可实现未定义时关联到默认函数unused未使用也不输出警告信息