arm裸机开发
程序员文章站
2022-07-14 15:18:41
...
GNU常用工具
GNU组织不仅给我们带来了许多开源软件 工程,还带来了强大的GNU编译工具
- 预处理器 cpp
- C编译器 gcc
- C++编译器 g++
- 汇编器 as
- 链接器 ld
- 二进制工具集 objcopy、objdump、……
1、nm:符号显示器
$nm -n main_elf
- 第一列为符号地址
- 第二列为符号所在段
- 第三列为符号名称
段 | 描述 |
---|---|
b/B | .bss(b静态/B非静态)未初始化变量 |
d/D | .data(d静态/D非静态)已初始化变量 |
r/R | .rodata(r静态/R非静态)只读数据段 |
t/T | .text(t静态/T非静态)函数 |
A | 不可改变的绝对值 |
C | .o中未初始化非静态变量 |
N | 调试用的符号 |
U | 表示符号只有声明没有定义 |
1.1、nm符号显示器总结:
- 静态变量和非静态的全局变量,所分配的段只与其是否 初始化有关,如果初始化了则被分配 在.data段中,否 则在.bss段中
- 函数无论是静态还是非静态的,总是被分配在.text中, 小写t表示静态,大写T表示非静态
- 函数内的局部变量由于是分配在栈上的,所以在nm中是 看不到他们的
2、objdump:信息查看器
- 查看所有段信息 $objdump -h main_elf
- 查看文件头信息 $objdump -f main_elf
- 查看反汇编 $objdump -d main_elf
- 查看内嵌反汇编 $objdump -S -d main_elf
- 可以查看有哪些段和段里面的信息 $objdump -s main_elf
3、objcopy:段剪辑器
剪除elf格式信息,这样才能在裸机状态下执行
- 去除elf格式信息 $objcopy -O binary -S main_elf main.bin
程序的编译链接过程
最后一步是将目标文件交给链接器链接生成 可执行文件
- gcc -E -o main.i main.c
- gcc -S -o main.S main.i
- gcc -c -o main.o main.S
- gcc -o main_elf main.o
1、什么是链接
将所用到的文件, 吧相应的代码放到相应的段里面,并给每个段安排一个起始地址;
- 用户通常并不直接参与链接过程
- 一个标准应用程序通常都由链接器采用默 认链接脚本(arm-linux-ld --verbose)将“用户 程序”和“库”共同链接生成可执行程序
- 假如不采用系统给定的默认链接脚本,我 们应该怎样进行链接?
ld -o main main.o
结论:
- 链接过程中需要一个标号(_start)作为程序入口
- 标号(_start)的作用是:将用户程序从汇编带到了C语 言程序入口,即main()函数,从此开始我们的应用程序 之旅
- start标号所在的汇编文件在编译工具链下面: 4.3.2/arm-none-linux-gnueabi/libc/usr/lib/crt1.o
- 如果没有crt1.o等标准库文件,我们可以自己实现_start入口,或者重新指定 一个新的入口
手动链接并生成可执行文件过程如下:
- 直接通过参数指定程序入口和段地址: arm-linux-ld -Ttext=0x30000 -Tdata=0x40000 -e main -o app head.o main.o
- 通过链接脚本来指定程序入口和段地址: arm-linux-ld -Tapp.lds -o app head.o main.o
//连接文件app.lds为:
ENTRY(main)
SECTIONS
{
//“*”号指所有目标,可以指定.o目标文件,多个用空格隔开
.=0x30000;//“.”指的是当前位置
.text:{*(.text)}
.=0x40000;
.data:{*(.data)}
.bss:{*(.bss)}
}
为什么需要我们自己完成链接过程?
裸机工程构建及调试
1、裸机程序完整编译过程:
案例,打印 hello IoT
int main()
{
char *str = "\nhello IoT";
char *p = 0xc00a1020;
int i = 11;
while(i--)
{
*p = *str++;
}
return 0;
}
裸机程序完整编译过程:
arm-linux-gcc -c -o t.o t.c //只编译不连接
arm-linux-ld -o t t.o -e main -Ttext=0x47000000 //手动连接
arm-linux-objcopy -O binary -S t t.bin
使用超级终端:
设置串口默认下载地址:
setenv loadaddr 0x47000000
查看设置的环境变量:printenv
上传.bin文件:loadb
运行:go 0x47000000