编译、链接、汇编过程

注意 !,本开发板为正点原子IMX6ULL_Mini开发板,不同点为程序链接地址不同

预编译(Precompile)

将头文件、宏的值展开带到程序里

编译 (Compile)

main.c → main.s

汇编(Assembly)

main.s→main.o

将多个xxx.o文件拼接起来,链接成不带后缀的main(ELF)文件

此文件在Linux中可直接运行,但是在单片机中还需要生成为二进制文件

生成二进制文件

将main(ELF)中的无用信息剥离,变为main.bin

编写boot

第一个我们要进行汇编。把mystart.s变成mystart.o。把mylowleve变成mylowleve.o 进行链接。是把这两个文件统合。我们把他起个名字叫myboot这个文件是elf格式的。 生成二进制文件,把myboot中的段信息,调试信息去掉,变为myboot.bin 制作镜像,使用正点原子提供的**(imxdownload),将myboot.bin变为myboot.imx**并烧录到SD卡中

mystart.s

b reset 
b reset
b reset
b reset
b reset
b reset
b reset
b reset

reset:
    bl gpio_out
    bl led_on 
    mov r0, r1 //跳过流水线
    mov r1, r2//跳过流水线
    mov r2, r3//跳过流水线
    mov r3, r4//跳过流水线
    mov r4, r5//跳过流水线

1:
    b 1b //死循环
gpio_out:
    /* 1、使能所有时钟 */
	ldr r0, =0X020C4068 	/* CCGR0 */
	ldr r1, =0XFFFFFFFF  
	str r1, [r0]		
ldr r0, =0X020C406C  	/* CCGR1 */
str r1, [r0]

ldr r0, =0X020C4070  	/* CCGR2 */
str r1, [r0]

ldr r0, =0X020C4074  	/* CCGR3 */
str r1, [r0]

ldr r0, =0X020C4078  	/* CCGR4 */
str r1, [r0]

ldr r0, =0X020C407C  	/* CCGR5 */
str r1, [r0]

ldr r0, =0X020C4080  	/* CCGR6 */
str r1, [r0]
/* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
ldr r0, =0X020E0068	    /* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
ldr r1, =0X5		              /* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
str r1,[r0]

/* 3、配置GPIO1_IO03的IO属性	
 *bit 16:0 HYS关闭
 *bit [15:14]: 00 默认下拉
 *bit [13]: 0 kepper功能
 *bit [12]: 1 pull/keeper使能
 *bit [11]: 0 关闭开路输出
 *bit [7:6]: 10 速度100Mhz
 *bit [5:3]: 110 R0/6驱动能力
 *bit [0]: 0 低转换率
 */
ldr r0, =0X020E02F4	    /*寄存器SW_PAD_GPIO1_IO03_BASE */
ldr r1, =0X10B0
str r1,[r0]

/* 4、设置GPIO1_IO03为输出 */
ldr r0, =0X0209C004	    /*寄存器GPIO1_GDIR */
ldr r1, =0X0000008		
str r1,[r0]
mov pc ,lr //从子程序返回

mylowleve.s

.global led_on
led_on:
	/* 打开LED0

设置GPIO1_IO03输出低电平
*/
ldr r0, =0X0209C000	/*寄存器GPIO1_DR */
ldr r1, =0		
str r1,[r0]
mov pc,lr //从子程序返回

进行汇编

arm-linux-gnueabihf-as mystart.s -o mystart.o

arm-linux-gnueabihf-as mylowleve.s -o mylowleve.o

也可以用

arm-linux-gnueabihf-gcc -c mystart.s

arm-linux-gnueabihf-gcc会在内部判断当前文件是为xxx.s而调用arm-linux-gnueabihf-as

xxx.o文件内部

包含三个段 .text //代码段

.data //初始化的全局变量

.bss //未初始化,系统自动设置为0

举个梨子

创建main.c文件

long a[3] = {1,2,3};

int main()  {
    return 0;
}

编译

arm-linux-gnueabihf-gcc -c main.c 

查看xxx.o文件

arm-linux-gnueabihf-size main.o

  • text表示代码长度为16
  • data表示初始化的变量为12(long为4字节,3各元素12个字节)
  • bss为0
  • dec为10进制
  • hex为16进制

改变main.c文件

long a[3] = {0};

int main()  {
    return 0;
}

再次编译查看

此时data为0,而bss为12,这就是data与bss的区别

链接

大致流程

将 .text 与 .text 段链接在一起

将 .data 与 .data 段链接在一起

将 .bss 与 .bss 亿链接在一起

建立myboot.lds文件

SECTIONS
{
        . = 0X87800000;
        .text : {
                mystart.o 
                * (.text)      
        }
        .data : {
                * (.data)
        }
        .bss_start =  . ;
        .bss : {
                * (.bss)
        }
        .bss_end = . ;
}

使用命令链接

 arm-linux-gnueabihf-ld -Tmyboot.lds -o myboot mystart.o mylowleve.o

myboot 就是我们生成的ELF文件

将myboot(ELF)转换为myboot.bin

arm-linux-gnueabihf-objcopy -O binary myboot myboot.bin

烧录

使用正点原子的imxdownload工具将myboot.bin文件烧录到SD卡中

将sd卡插入开发板中,拨码拨到sd卡启动,上电,可以看到开发板的LED被电亮