嵌入式开发学习日志Day7(ARM体系架构——GUN工具链常用工具、SDK工具及链接脚本、Makefile)
1. .bss段用于存放未初始化或初始化为0的数据在运行时会被自动清零- 典型例子://静态变量(全局或局部)//显式初始化为0的全局变量2.COMMON段用于存放未初始化的非静态全局变量链接时才确定最终大小和位置允许多个目标文件定义同名符号- 典型例子://未初始化的非静态全局变量3. .data段用于存放已初始化的全局变量和静态变量(非零值)需要在程序文件中保存实际的初始值- 典型例子://
一、GUN工具链常用工具说明及Makefile编写
1.1 GUN工具链常用工具
gcc (GNU Compiler Collection)
功能:编译器(Compiler)
- 将C/C++等高级语言源代码转换为汇编代码
- 再将汇编代码转换为目标文件,生成.o文件
- 支持多种编程语言和目标平台
- 提供丰富的优化选项和编译控制选项
eg:arm-linux-gnueabihf-gcc -c -g -o start.o start.S
ld (GNU Linker)
功能:链接器(Linker)
- 将多个目标文件链接成可执行文件,生成.elf文件
- 解析和处理符号引用
- 进行地址分配和重定位
- 处理库文件的链接
eg:arm-linux-gnueabihf-ld -Ttext 0x87800000 -ostart.elf start.o
objcopy (Binary File Converter)
功能:目标文件格式转换器
- 在不同格式的目标文件之间进行转换
- 将ELF格式转换为纯二进制格式(.bin)
- 从目标文件中提取特定的段(sections)
- 修改目标文件的内容
- 常用于嵌入式开发中的固件生成
eg:arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin
objdump (Object File Disassembler)
功能:目标文件分析器/反汇编器
- 将机器码反汇编为汇编代码
- 查看目标文件的详细信息
- 分析程序的执行指令
- 显示各种文件格式信息
eg: arm-linux-gnueabihf-objdump -D start.elf > start.dis
1.2 编写Makefile文件(方便后期使用)

优化1:$@指的是目标 $^指的是源 内部自动寻找,并产生

优化2:

clean:
rm *.o $(name).o $(name).elf $(name).bin $(name).dis -rf
clean——用来删除编译过程中产生的中间产物:
-rf————“-r”表示删除文件夹,,,“-f”如果删除过程中没有这个文件,则不会报错
1.3 编写C代码
使用CPS指令,在汇编start.S中设置irq寄存器,system寄存器中的栈存储地址;
volatile (易变的、多变的):禁止编译器进行优化,必须根据指针间接访问所指向的地址;
功能引脚:
方向寄存器:
数据寄存器:
代码展示:
二、SDK(软件开发工具)
- 直接使用定义好的相关寄存器,节省时间
2.1 SDK使用原理
寄存器地址是连续的,利用结构体装载内容,并宏定义该结构体的首地址;
2.1 SDK代码的使用
main.c
#include "MCIMX6Y2.h" #include "fsl_iomuxc.h" void enable_all_clocks(void) { CCM->CCGR0 = 0xFFFFFFFF; CCM->CCGR1 = 0xFFFFFFFF; CCM->CCGR2 = 0xFFFFFFFF; CCM->CCGR3 = 0xFFFFFFFF; CCM->CCGR4 = 0xFFFFFFFF; CCM->CCGR5 = 0xFFFFFFFF; CCM->CCGR6 = 0xFFFFFFFF; } void delay(unsigned int n) { while(n--); } int main(void) { enable_all_clocks(); init_led(); while(1) { led_nor(); delay(0xFFFFF); } }
led.c
#include"MCIMX6Y2.h" #include"fsl_iomuxc.h" #include "led.h" void init_led(void) { IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0); GPIO1->GDIR |= (1 << 3); GPIO1->DR &= ~(1 << 3); } void led_on(void) { // GPIO1_DR &= ~(1 << 3); GPIO1->DR &= ~(1 << 3); } void led_off(void) { // GPIO1_DR |= (1 << 3); GPIO1->DR |= (1 << 3); } void led_nor(void) { // GPIO1_DR ^= (1 << 3); GPIO1->DR ^= (1 << 3); }
三、链接脚本
3.1 内存段介绍
1. .bss段
用于存放未初始化或初始化为0的数据
在运行时会被自动清零
- 典型例子:
static int bss_var; // 静态变量(全局或局部)
int explicit_var = 0; // 显式初始化为0的全局变量
2.COMMON段
用于存放未初始化的非静态全局变量
链接时才确定最终大小和位置
允许多个目标文件定义同名符号
- 典型例子:
int common_var; // 未初始化的非静态全局变量
3. .data段
用于存放已初始化的全局变量和静态变量(非零值)
需要在程序文件中保存实际的初始值
- 典型例子:
int global_var = 100; // 初始化为非零值
int global_array[] = {1,2,3}; // 初始化为非零数组
4. .rodata段(只读数据段)
- 存放程序的只读数据
- 运行时受保护,不可修改
- 包含的数据类型:
1. 字符串常量
2. const修饰的全局变量
3. 全局只读数组
4. switch跳转表
5. 浮点数常量
- 典型例子:
const int MAX_VALUE = 100; // const全局变量
char* str = "Hello World"; // 字符串常量
const int lookup[] = {1,2,3}; // 只读数组
5. .text段(代码段)
## 各段的特点比较
| 段名 | 初始化 | 运行时可写 | 链接特性 |
|--------------------|-------------------|--------------------|--------------------|
| .bss | 自动清零 | 可写 | 编译时确定大小 |
| COMMON | 自动清零 | 可写 | 链接时确定大小 |
| .data | 需要初始值 | 可写 | 编译时确定大小 |
| .rodata | 需要初始值 | 只读 | 编译时确定大小 |
3.2 链接脚本(不同的段放在哪里)
- 按四字节对齐//ALIGN(4)




更多推荐







所有评论(0)