其实编译过程很简单,就是,例如:

在终端输入如下命令:
gcc main.c calcu.c input.c -o main

即可把上述3个c文件编译为可执行的main文件,但是当一个工程包含数百个xx.c文件,此时上述直接写,就很麻烦,而且哪些文件新修改了,需要再次编译或者不需要再次编译,程序员都很难自己掌控,很麻烦。这时候makefile就登场了,自动化控制编译过程。看我这篇文章gcc编译器使用总结和makefile基本知识

1 main: main.o input.o calcu.o
2         gcc -o main main.o input.o calcu.o
3 main.o: main.c
4         gcc -c main.c
5 input.o: input.c
6         gcc -c input.c
7 calcu.o: calcu.c
8         gcc -c calcu.c

10 clean:
11         rm *.o
12         rm main
 

arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^
上面语句中我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件
都会链接到以 0X87800000 为起始地址的区域。

但是如果说我们为了自己定位程序运行地址(比如自己做程序动态加载),需要自己去链接它们,而且程序中的段(每个xx.o文件都包含text,data段)也自己去统一指定内存区域(这是可以的,因为链接时候符号定位地址知道即可),要完成这个功能我们就需要使用到链接脚本。说是链接脚本,可以说是定位脚本。

改为:
arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^

我们一般编译出来的代码
都包含在 text、data、bss 和 rodata 这四个段内,假设现在的代码要被链接到 0X10000000 这个
地址,数据要被链接到 0X30000000 这个地方,下面就是完成此功能的最简单的链接脚本:

1 SECTIONS{
2         . = 0X10000000;
3         .text : {*(.text)}
4         . = 0X30000000;
5         .data ALIGN(4) : { *(.data) } 
6         .bss ALIGN(4) : { *(.bss) } 
7 }

“.”在链接脚本里面叫做定位计数器,默认的定位
计数器为 0。

“.text”是段名,后面的冒号是语法要求,冒号后面的大括号里面可以填上要链
接到“.text”这个段里面的所有文件,“*(.text)”中的“*”是通配符,表示所有输入文件的.text
都放到“.text”中。

ALIGN(4)表示 4 字节对齐。也就是说段“.data”的起始地址要能被 4 整
除,一般常见的都是 ALIGN(4)或者 ALIGN(8)

我们本试验的链接脚本要求如下:
①、链接起始地址为 0X87800000。
②、start.o 要被链接到最开始的地方,因为 start.o 里面包含这第一个要执行的命令。

1 SECTIONS{
2         . = 0X87800000;
3         .text :
4         {
5                 start.o 
6                 main.o 
7                 *(.text)
8         }
9         .rodata ALIGN(4) : {*(.rodata*)} 
10         .data ALIGN(4) : { *(.data) } 
11         __bss_start = .; 
12         .bss ALIGN(4) : { *(.bss) *(COMMON) } 
13         __bss_end = .;
14 }

第5行设置链接到开始位置的文件为start.o,
因为 start.o 的text段里面包含着第一个要执行的指令,所以一定要链接到最开始的地方。第 6 行是 main.o
这个文件,其实可以不用写出来,因为 main.o 的位置就无所谓了,可以由编译器自行决定链接
位置。(因为链接时候符号定位地址知道即可)

“__bss_start”
和“__bss_end”是符号,第 11、13 这两行其实就是对这两个符号进行赋值,其值为定位符“.”,
这两个符号用来保存.bss 段的起始地址和结束地址。

我们需要手动对.bss 段的变量清零的,因此我们需要知道.bss 段的起始和结束地址,
这样我们直接对这段内存赋 0 即可完成清零。通过第 11、13 行代码,.bss 段的起始地址和结束
地址就保存在了“__bss_start”和“__bss_end”中,我们就可以直接在汇编或者 C 文件里面使
用这两个符号。

注:

链接脚本文件是xx.lds

stm32反汇编文件是xx.lst