我們一般在Windows下的MDK環境或者是ADS環境下開發裸機程式
下面來體驗一下Linux下GNU-ARM的裸奔程式開發
GNU ARM裸奔程式的開發步驟如下:
1)編寫程式(彙編/C程式)
2)編寫連結腳本
3)編譯、彙程式設計式檔案,生産目标檔案(.o)
4)利用連結腳本連結目标檔案,生産可執行檔案(elf格式)
5)利用格式轉換工具(objcopy)将elf格式檔案轉換為bin格式
6)燒寫
這裡彙編指令就略過了。
彙編行結構
[标号:] 彙編語句 @注釋
标号
标号隻能由a~z,A~Z,0~9,“.”,“_”等字元組成;
“.” 标号 :特殊的标
“_”表示目前位置的運作位址 ;
注釋
@ 從符合開始到行結尾
# 整行注釋
彙程式設計式中的分段
彙編系統預定義的段名
.text @代碼段
.data @已經初始化的全局變量和靜态變量
.bss @是未初始化的全局變量和靜态變量
自定義一個段
.section 自定義段名
彙程式設計式中的關鍵字
.extern symbol
聲明symbol的定義在其他源檔案中
.global symbol
聲明symbol是全局可見的
.include "filename"
在目前源檔案中插入filename的内容
.set symbol, expression
設定symbol的值為expression
GNU的僞指令跟MDK的僞指令不同;但是兩個編譯器都能夠識别ARM指令;
GNU編譯環境下的僞操作可分為以下幾類:
常量編譯控制僞操作
彙程式設計式代碼控制僞操作
宏及條件編譯控制僞操作
其他僞操作
常量編譯控制僞操作

彙程式設計式代碼控制僞操作
宏及條件編譯控制僞操作
其他僞操作
連接配接腳本檔案
elf格式檔案:
GNU編譯器生成的目标檔案預設為elf格式;
elf檔案由若幹段(section)組成;
目标代碼中包含如下段:
.text: 包含程式的指令代碼;
.data: 包含固定的資料,如常量、字元串;
.bss: 包含未初始化的變量、數組等;
連接配接器的任務就是将多個目标檔案的.text、.data和.bss等段連接配接在一起,而連接配接腳本檔案是告訴連接配接器從什麼位址開始放置這些段。
連結腳本
内置預設連接配接腳本:
如果采用預設腳本,則生成的目标代碼需要作業系統才能加載運作(作業系統上的應用程式采用預設腳本)。
自定義連結腳本:
為了能在嵌入式系統上直接運作,需要編寫自己的連接配接腳本檔案。
連結腳本格式
連結器腳本由一系列指令組成;
“SECTIONS”指令:描述輸出檔案的記憶體布,SECTIONS段的基本格式如下:
SECTIONS
{
段名 : {段内容}
}
ENTRY(symbol) :設定入口點,參數是一個符号名;
OUTPUT_FORMAT(bfdname):輸出檔案的BFD格式;
OUTPUT_ARCH(bfdarch) :指定平台架構;
對于ARM,bfdname=elf32-littlearm,bfdarch=arm
LED跑馬燈程式連結腳本:
led.lds:
1 OUTPUT_FORMAT(elf32-littlearm)
2 OUTPUT_ARCH(arm)
3 ENTRY(_start)
4
5 SECTIONS
6 {
7 >---. = 0x0;
8 >---. = ALIGN(4);
9 >---.text : {
10 >--->---led.o (.text)
11 >--->---delay.o (.text)
12 >---}
13
14 >---. = ALIGN(4);
15 >---.data : {
16 >--->---*(.data)
17 >---}
18 >---
19 >---. = ALIGN(4);
20 >---.bss : {
21 >--->---*(.bss)
22 >---}
23
24 }
編譯連結過程
Arm-linux-ld –Txxx.lds xx.o –o xxxx.elf
–T 直接指定代碼段
xxx.lds 為連接配接腳本
arm-linux-objcopy被用來複制一個目标檔案的内容到另一個檔案中,可用于不同源檔案的之間的格式轉換
Arm-linux-objcopy –O binary –S elf_file bin_file
-O bfdname 輸出的格式
-F bfdname 同時指明源檔案,目的檔案的格式
-R sectionname 從輸出檔案中删除掉所有名為sectionname的段
-S 不從源檔案中複制重定位資訊和符号資訊到目标檔案中
-g 不從源檔案中複制調試符号到目标檔案中
makefile:
1 led.bin:led.o delay.o led.lds
2 >---arm-linux-ld -Tled.lds led.o delay.o -o led.elf
3 >---arm-linux-objcopy -O binary -S led.elf led.bin
4
5 led.o:led.s
6 >---arm-linux-gcc -c led.s -o led.o>
7
8 delay.o:delay.s
9 >---arm-linux-gcc -c delay.s -o delay.o
10
11 clean:-
12 >---rm -rf *.o *.elf *.bin
13
led.s:
.text
.extern delay
.global _start
_start:
@set GPBCON
ldr r0,=0x56000010
ldr r1,[r0]
bic r1,r1,#0xc00
orr r1,r1,#0x15400
str r1,[r0]
@set GPBUP
ldr r0,=0x56000018
ldr r1,[r0]
orr r1,r1,#0x20
str r1,[r0]
loop:
ldr r0,=0x56000014
ldr r3,=0x1e0
str r3,[r0]
bl delay
ldr r3,=0xfd0
str r3,[r0]
bl delay
ldr r3,=0xfb0
str r3,[r0]
bl delay
ldr r3,=0xf70
str r3,[r0]
bl delay
ldr r3,=0xef0
str r3,[r0]
bl delay
b loop
.end
delay.s:
1
2 .text
3 .global delay
4 delay:
5 >---ldr r2,=0x2000000
6 delay_loop:
7 sub r2,r2,#1
8 cmp r2,#0x0
9 bne delay_loop
10 mov pc,lr
11
12 .end
最後,把make出來的bin燒到闆上。
假如用jtag可以燒到0位址。此時cup頻率是12mhz,delay.s下的ldr r2,=0x20000,此時開發闆上的bootloader已經挂了,是以不推薦用這種方法。
假如用dnw下到記憶體裡運作,此時的cup頻率是400mhz,delay.s下的ldr r2,=0x2000000,ok