【嵌入式開發】 嵌入式開發工具簡介 (裸板調試示例 | 交叉工具鏈 | Makefile | 連接器腳本 | eclipse JLink 調試環境)

做者 : 韓曙亮linux

博客地址http://blog.csdn.net/shulianghan/article/details/42239705 ios

參考博客 【嵌入式開發】嵌入式 開發環境 (遠程登陸 | 文件共享 | NFS TFTP 服務器 | 串口鏈接 | Win8.1 + RedHat Enterprise 6.3 + Vmware11)c++



開發環境sass

-- 操做系統 : Vmware11 + RedHat6.3 企業版 + Win8.1;bash

-- 硬件 : OK-6410-A 開發板, JLink;服務器



一. 編譯並燒寫裸板程序示例



1. 設置交叉編譯工具


OK-6410-A 使用 4.3.2 的交叉編譯工具鏈, 將交叉編譯工具鏈設置成 Ubuntu 的默認交叉編譯工具鏈;app


安裝交叉編譯工具鏈 : 解壓 arm-linux-gcc-4.3.2.tgz 文件 eclipse

-- 安裝命令 : 使用命令 tar -xvzf arm-linux-gcc-4.3.2.tgz -C /, 因爲 tgz 壓縮文件內也是存在目錄結構, 解壓後, 交叉編譯工具鏈直接解壓到了 /usr/local/arm/4.3.2 目錄;ide

-- 配置環境變量 : 環境變量在 /etc/profile 中配置, 在該文件中添加以下代碼 : 工具

ARM_LINUX="/usr/local/arm/4.3.2/bin"
export PATH=$PATH:$ARM_LINUX
-- 使配置文件生效 : 執行 source /etc/profile 命令, 該配置便可生效, 執行 arm-linux 按 tab 鍵 : 

octopus@octopus:~$ arm-linux-
arm-linux-addr2line  arm-linux-c++filt    arm-linux-gcc-4.3.2  arm-linux-gprof      arm-linux-objdump    arm-linux-sprite
arm-linux-ar         arm-linux-cpp        arm-linux-gcov       arm-linux-ld         arm-linux-ranlib     arm-linux-strings
arm-linux-as         arm-linux-g++        arm-linux-gdb        arm-linux-nm         arm-linux-readelf    arm-linux-strip
arm-linux-c++        arm-linux-gcc        arm-linux-gdbtui     arm-linux-objcopy    arm-linux-size  



2. 編譯代碼



(1) 代碼示例


代碼直接是開發板的示例代碼:

-- led.S

octopus@octopus:~/arm/01_code$ more led.S 
.text
.globl _start
#define VIC0_INT	0x71200000
#define VIC1_INT	0x71300000

_start: bl reset
		ldr	pc, _undefined_instruction
		ldr	pc, _software_interrupt
		ldr	pc, _prefetch_abort
		ldr	pc, _data_abort
		ldr	pc, _not_used
		ldr	pc, _irq
		ldr	pc, _fiq
_undefined_instruction:b .
_software_interrupt:b .
_prefetch_abort:b .
_data_abort:b .
_not_used:b .
_irq:b .
_fiq:b .
reset:
		mrs	r0,cpsr
		bic	r0,r0,#0x1f
		orr	r0,r0,#0xd3
		msr	cpsr,r0

		bl set_peri_port
		bl disable_watchdog
		bl disable_irq
		bl init_led
		bl light_led

halt:
		bl halt

set_peri_port:
@告訴cpu外設的地址
	    ldr r0, =0x70000000
	    orr r0, r0, #0x13
	    mcr p15,0,r0,c15,c2,4
		mov	pc, lr

disable_watchdog:
@關閉看門狗
		ldr r0, =0x7E004000
		mov r1, #0
		str r1, [r0] @ str, store,
		mov	pc, lr

disable_irq:
@屏蔽中斷
		ldr	r1, =0x0
		ldr	r0, =VIC0_INT
		str	r1, [r0]

		ldr	r1, =0x0
		ldr	r0, =VIC1_INT
		str	r1, [r0]
		mov	pc, lr

init_led:
@設置GPN爲輸出模式
		ldr r1, =0x7F008820
		ldr r0, =0x1111
		str r0, [r1]
		mov	pc, lr

light_led:
@點亮LED1
		ldr r1, =0x7F008824
		mov r0, #0xf
		str r0, [r1]
	    mov r0,#0xe
	    str r0,[r1]
	    mov	pc, lr
-- led.lds

octopus@octopus:~/arm/01_code$ more led.lds 


OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x50008000;

	. = ALIGN(4);
	.text :
	{
		led.o	(.text)
		*(.text)
	}

	. = ALIGN(4);
	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

	. = ALIGN(4);
	.data : { *(.data) }


	. = ALIGN(4);
	__bss_start = .;
	.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
	_end = .;
}

-- Makefile

octopus@octopus:~/arm/01_code$ more Makefile 
all: led.o 
	arm-linux-ld -Tled.lds -o led.elf led.o
	arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o led.o -c led.S
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin



(2) 編譯


編譯 : 在該目錄執行 make 命令, 編譯後多了 led.o, led.elf, led.bin 三個文件, 其中 led.bin 是要燒寫到 nand flash 中的可執行二進制程序;

-- 編譯前

octopus@octopus:~/arm/01_code$ ls
led.lds  led.S  Makefile

-- 編譯後

octopus@octopus:~/arm/01_code$ make
arm-linux-gcc -g -o led.o -c led.S
arm-linux-ld -Tled.lds -o led.elf led.o
arm-linux-objcopy -O binary led.elf led.bin
octopus@octopus:~/arm/01_code$ ls
led.bin  led.elf  led.lds  led.o  led.S  Makefile


3. 燒寫 led.bin


(1) 啓動方式切換


sd 卡啓動 : (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1;

nand flash 啓動 : (1~8) 位置 : x, x, x, 1, 1, 0, 0, 1;

nor flash 啓動 (1~8) 位置 : x, x, x, 1, 0, 1, 0, x;



(2) 製做SD卡啓動盤


詳細過程參照http://blog.csdn.net/shulianghan/article/details/42254237#t42


(3) 串口操做


開發板串口方案一 -- 使用SecureCRT 串口鏈接

-- 設備管理器中查看串口端口 : COM7;


-- 串口鏈接屬性


-- 鏈接串口




開發板串口方案二 -- 打開 minicom 工具 : minicom 串口調試工具;

-- 注意 : 使用 root 用戶打開, sudo minicom;


sd 卡啓動

-- 啓動方式 : 插入 sd 卡, 將啓動模式設置爲 sd 卡啓動, 即將 屏幕右側的 8個開關設置成 (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1, 打開電源;

-- 注意 : 打開電源時 不停按 空格鍵;

-- 串口端顯示

U-Boot 1.1.6 (Oct  9 2012 - 13:20:58) for SMDK6410

****************************************
**    u-boot 1.1.6                    **
**    Updated for OK6410  TE6410 Board  **
**    Version (2012-09-23)          **
**    OEM: Forlinx Embedded           **
**    Web: http://www.witech.com.cn   **
****************************************

CPU:     S3C6410 @532MHz
         Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz, Serial = CLKUART (SYNC Mode) 
Board:   SMDK6410
DRAM:    256 MB
Flash:   0 kB
NandFlash Information:
Nandflash:ChipType= SLC  ChipName=MT29F16G08ABACAWP
No  No Calc pagesize, blocksize, erasesize,  use ids table .............
NandFlash:name=NAND 2GiB 1,8V 8-bit,id=38, pagesize=4096 ,chipsize=1024 MB,erasesize=524288 oobsize=128
NandFlash Size is 1024 MB 
SD/MMC:  SD 2.0 / Manufacturer: 0x1B,OEM: "SM/00000",REV: 1.0,S/N: -1320320343,DATE: 2008/3
         MMC/SD size: 971 MiB
         Freq = 25MHz
In:      serial
Out:     lcd
Err:     lcd
Hit any key to stop autoboot:  0 

###################### User Menu for OK6410#####################
[1] Format the nand flash
[2] Burn image from SD card
[3] Burn image from USB
[4] Reboot the u-boot
[5] Exit to command line
-----------------------------Select---------------------------------
Enter your Selection: 


格式化 nand flash : 在上面的 minicom 命令行, 選擇 1 ([1] Format the nand flash -- 格式化 nand Flash), 彈出 Really scrub this NAND flash? <y/N> 時 選擇 y;

-----------------------------Select---------------------------------
Enter your Selection:1

NAND scrub: device 0 whole chip
Warning: scrub option will erase all factory set bad blocks!
         There is no reliable way to recover them.
         Use this command only for testing purposes if you
         are sure of what you are doing!

Really scrub this NAND flash? <y/N>
Erasing at 0x3ff80000 -- 100% complete.
Scanning device for bad blocks
OK

###################### User Menu for OK6410#####################
[1] Format the nand flash
[2] Burn image from SD card
[3] Burn image from USB
[4] Reboot the u-boot
[5] Exit to command line
-----------------------------Select---------------------------------
Enter your Selection:


選擇從 usb 燒寫映像 : 選擇 3 ([3] Burn image from USB -- 從usb燒寫映像);

-----------------------------Select---------------------------------
Enter your Selection:3

##### Select the fuction #####
[1] Flash u-boot
[2] Flash kernel
[3] Flash system
[4] Exit
Enter your Selection:


選擇 燒寫 u-boot 類型程序 : 裸板程序都屬於 u-boot 類型的;

##### Select the fuction #####
[1] Flash u-boot
[2] Flash kernel
[3] Flash system
[4] Exit
Enter your Selection:1

NAND erase: device 0 offset 0x0, size 0x200000
Erasing at 0x180000 -- 100% complete.
OK
Insert a OTG cable into the connector!


設置虛擬機的 USB 接口 : 以前寫過, 詳情見 http://blog.csdn.net/shulianghan/article/details/42254237#t45 ;


(3) Linux 操做


編譯 led 源碼

-- 進入 led 源碼目錄 : 執行 make 命令, 將編譯後的文件 拷貝到 dnw 所在目錄;



燒寫 led.bin

-- 加載 dnw 驅動 : 使用 insmod dnw_usb.ko 命令;


-- 燒寫 led.bin : 使用 ./dnw led.bin 50008000 命令;


-- 串口終端顯示 : 以下顯示, 燒寫成功;


-- 關閉開發板使用 nand flash 啓動 : 能夠看到 LED1 點亮;




二. 交叉工具鏈




1. 交叉編譯器



(1) 普通編譯


編譯下面的代碼

/*************************************************************************
    > File Name: main.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: 2015年01月03日 星期六 14時25分11秒
 ************************************************************************/

#include<stdio.h>
int main(int argc, char** argv)
{
	printf("Hello World!\n");
	return 0;
}
-- 編譯執行代碼

[root@localhost 02_gcc_demo]# gcc main.c 
[root@localhost 02_gcc_demo]# ./a.out 
Hello World!



(2) 交叉編譯並在開發板運行


交叉編譯 : 使用 arm-linux-gcc main.c 命令交叉編譯, 通過交叉編譯的 a.out 不能再 x86 平臺執行;



使用 U 盤將程序拷貝到開發板 : 將 a.out 拷貝到 U 盤, 而後將 U 盤拷貝到開發板上;

-- 拷貝命令cp a.out /media/UUI/, UUI 是 U 盤名稱;

-- 開發板插入 U 盤 : 將 U 盤插入開發板(已安裝 Linux 操做系統) USB 口, 根目錄下出現 udisk 目錄, 該目錄就是 U 盤;

-- 執行交叉編譯後的程序 : 執行 a.out 程序, 執行成功;




(3) 交叉|普通編譯結果對比



對比交叉編譯 和 普通編譯 的可執行文件 : 經過 file 命令對比可執行文件;

-- 交叉編譯 : 使用 arm-linux-gcc main.c -o hello-arm 命令交叉編譯結果 hello-arm, 使用 file hello-arm 命令查看文件屬性;

root@localhost 02_gcc_demo]# file hello-arm 
hello-arm: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.14, not stripped

-- 普通編譯 : 使用 gcc main.c -o hello-x86 命令普通編譯結果 hello-x86, 使用 file hello-x86 命令查看文件屬性;

[root@localhost 02_gcc_demo]# file hello-x86 
hello-x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped



(4) 查找目錄



查看查找目錄 : 使用 arm-linux-gcc -print-search-dirs 命令查看;

[root@localhost ~]# arm-linux-gcc -print-search-dirs
install: /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/
programs: =/usr/local/arm/4.3.2/bin/../libexec/gcc/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../libexec/gcc/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/bin/
libraries: =/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/:/usr/local/arm/4.3.2/bin/../lib/gcc/armv4t/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/lib/arm-none-linux-gnueabi/4.3.2/armv4t/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/lib/armv4t/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/lib/arm-none-linux-gnueabi/4.3.2/armv4t/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/lib/armv4t/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/usr/lib/arm-none-linux-gnueabi/4.3.2/armv4t/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/usr/lib/armv4t/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../lib/gcc/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/lib/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/../../../../arm-none-linux-gnueabi/lib/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/lib/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/lib/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/usr/lib/arm-none-linux-gnueabi/4.3.2/:/usr/local/arm/4.3.2/bin/../arm-none-linux-gnueabi/libc/armv4t/usr/lib/
[root@localhost ~]# 




2. 交叉連接器



(1) Makefile 示例


查看 led Makefile : 查看上面的 led 程序的 Makefile文件;

all: led.o 
	arm-linux-ld -Tled.lds -o led.elf led.o
	arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o led.o -c led.S
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin



(2) 交叉連接器連接過程



連接過程

-- 交叉編譯 : 使用 arm-linux-gcc -g -o led.o -c led.S 命令, 獲取 led.o 文件, 交叉編譯結果是 生成 led.o 文件;


-- 連接 : 連接 led.o 生成 led.elf 文件, 使用 arm-linux-ld -Tled.lds -o led.elf led.o 命令;


-- 連接器命令格式 : -T 後面跟着連接器腳本, 這裏 連接器腳本是 led.lds, -o 是連接器的生成結果名稱;




3. arm-linux-readelf 工具



(1) arm-linux-readelf 解讀 .elf 文件


arm-linux-readelf 使用示例 : 執行 arm-linux-readelf -a led.elf 命令, 解讀 led.elf 文件;

-- 小端處理器運行 : "Data:  2's complement, little endian" 表示在小端 CPU 上執行, 若是程序大小端 與 CPU 不一致, 便不能執行;

-- 運行平臺 : "Machine:  ARM" 表示該程序在 ARM 平臺運行;

[root@localhost 01_led]# arm-linux-readelf -a led.elf 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x50008000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          33344 (bytes into file)
  Flags:                             0x5000002, has entry point, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         1
  Size of section headers:           40 (bytes)
  Number of section headers:         10
  Section header string table index: 7

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        50008000 008000 0000e0 00  AX  0   0  4
  [ 2] .ARM.attributes   ARM_ATTRIBUTES  00000000 0080e0 000018 00      0   0  1
  [ 3] .debug_line       PROGBITS        00000000 0080f8 000064 00      0   0  1
  [ 4] .debug_info       PROGBITS        00000000 00815c 000045 00      0   0  1
  [ 5] .debug_abbrev     PROGBITS        00000000 0081a1 000014 00      0   0  1
  [ 6] .debug_aranges    PROGBITS        00000000 0081b8 000020 00      0   0  8
  [ 7] .shstrtab         STRTAB          00000000 0081d8 000066 00      0   0  1
  [ 8] .symtab           SYMTAB          00000000 0083d0 0001a0 10      9  23  4
  [ 9] .strtab           STRTAB          00000000 008570 0000c3 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x008000 0x50008000 0x50008000 0x000e0 0x000e0 R E 0x8000

 Section to Segment mapping:
  Segment Sections...
   00     .text 

There is no dynamic section in this file.

There are no relocations in this file.

There are no unwind sections in this file.

Symbol table '.symtab' contains 26 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 50008000     0 SECTION LOCAL  DEFAULT    1 
     2: 00000000     0 SECTION LOCAL  DEFAULT    2 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000     0 SECTION LOCAL  DEFAULT    6 
     7: 50008000     0 NOTYPE  LOCAL  DEFAULT    1 $a
     8: 5000803c     0 NOTYPE  LOCAL  DEFAULT    1 reset
     9: 50008020     0 NOTYPE  LOCAL  DEFAULT    1 _undefined_instruction
    10: 50008024     0 NOTYPE  LOCAL  DEFAULT    1 _software_interrupt
    11: 50008028     0 NOTYPE  LOCAL  DEFAULT    1 _prefetch_abort
    12: 5000802c     0 NOTYPE  LOCAL  DEFAULT    1 _data_abort
    13: 50008030     0 NOTYPE  LOCAL  DEFAULT    1 _not_used
    14: 50008034     0 NOTYPE  LOCAL  DEFAULT    1 _irq
    15: 50008038     0 NOTYPE  LOCAL  DEFAULT    1 _fiq
    16: 50008064     0 NOTYPE  LOCAL  DEFAULT    1 set_peri_port
    17: 50008074     0 NOTYPE  LOCAL  DEFAULT    1 disable_watchdog
    18: 50008084     0 NOTYPE  LOCAL  DEFAULT    1 disable_irq
    19: 500080a0     0 NOTYPE  LOCAL  DEFAULT    1 init_led
    20: 500080b0     0 NOTYPE  LOCAL  DEFAULT    1 light_led
    21: 50008060     0 NOTYPE  LOCAL  DEFAULT    1 halt
    22: 500080c8     0 NOTYPE  LOCAL  DEFAULT    1 $d
    23: 50008000     0 NOTYPE  GLOBAL DEFAULT    1 _start
    24: 500080e0     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    25: 500080e0     0 NOTYPE  GLOBAL DEFAULT  ABS _end

No version information found in this file.
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "4T"
  Tag_CPU_arch: v4T
  Tag_ARM_ISA_use: Yes
[root@localhost 01_led]# 


(2) arm-linux-readelf 解讀 可執行程序須要的庫文件


程序沒法運行排錯方法 : 

-- 運行平臺不對 : ARM 平臺 和 x86 平臺之間的程序不能互相運行;

-- CPU 大小端不對 : 大端格式的程序不能運行在小端 CPU 上;

-- 庫不對 : 使用 arm-linux-readelf -d hello-arm 查看程序運行須要的庫, "0x00000001 (NEEDED)  Shared library: [libc.so.6]", 表示須要有libc.so.6 庫;

[root@localhost 02_gcc_demo]# arm-linux-readelf -d hello-arm 

Dynamic section at offset 0x460 contains 24 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x8274
 0x0000000d (FINI)                       0x8428
 0x00000019 (INIT_ARRAY)                 0x10454
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001a (FINI_ARRAY)                 0x10458
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x00000004 (HASH)                       0x8168
 0x00000005 (STRTAB)                     0x81e0
 0x00000006 (SYMTAB)                     0x8190
 0x0000000a (STRSZ)                      65 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x10548
 0x00000002 (PLTRELSZ)                   32 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8254
 0x00000011 (REL)                        0x824c
 0x00000012 (RELSZ)                      8 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x822c
 0x6fffffff (VERNEEDNUM)                 1
 0x6ffffff0 (VERSYM)                     0x8222
 0x00000000 (NULL)                       0x0
[root@localhost 02_gcc_demo]# 




4. 反彙編器(arm-linux-objdump)



(1) 反彙編


反彙編示例arm-linux-objdump -D -S hello-arm, 太多, 省略後面幾百行;

[root@localhost 02_gcc_demo]# arm-linux-objdump -D -S hello-arm 

hello-arm:     file format elf32-littlearm

Disassembly of section .interp:

00008134 <.interp>:
    8134:	62696c2f 	rsbvs	r6, r9, #12032	; 0x2f00
    8138:	2d646c2f 	stclcs	12, cr6, [r4, #-188]!
    813c:	756e696c 	strbvc	r6, [lr, #-2412]!
    8140:	6f732e78 	svcvs	0x00732e78
    8144:	Address 0x00008144 is out of bounds.

Disassembly of section .note.ABI-tag:... ...



(2) 編譯附加調試信息


帶調試信息的反編譯

-- 交叉編譯帶調試信息arm-linux-gcc -g main.c 命令, 進行交叉編譯, 結果 a.out;

-- 反編譯arm-linux-objdump -S -D a.out 命令, 反編譯結果 每行 C 代碼都對應 彙編代碼;

... ...

#include<stdio.h>
int main(int argc, char** argv)
{
    837c:	e92d4800 	push	{fp, lr}
    8380:	e28db004 	add	fp, sp, #4	; 0x4
    8384:	e24dd008 	sub	sp, sp, #8	; 0x8
    8388:	e50b0008 	str	r0, [fp, #-8]
    838c:	e50b100c 	str	r1, [fp, #-12]
	printf("Hello World!\n");
    8390:	e59f0014 	ldr	r0, [pc, #20]	; 83ac <main+0x30>
    8394:	ebffffc8 	bl	82bc <_init+0x48>
	return 0;
    8398:	e3a03000 	mov	r3, #0	; 0x0
}

... ...



5. 文件格式轉換器(arm-linux-objcopy)




文件格式轉換

-- 轉換緣由 : elf 格式文件不能再 arm 處理器執行;

-- 轉換命令 : 進入 led 目錄, 繼續上面的 led 編譯, 連接 生成了 led.elf 文件, 執行 arm-linux-objcopy -O binary led.elf led.bin 命令, 將 elf 文件轉換爲 bin 文件;

-- 命令解析 : -O 表示輸出格式, -O binary 表示輸出二進制格式;





三. Makefile 文件




Makefile 示例

all: led.o 
	arm-linux-ld -Tled.lds -o led.elf led.o
	arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o led.o -c led.S
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin



1. Makefile 規則



(1) 普通規則



規則 : 用於說明文件生成過程;

-- 規則語法

target(目標)prerequisites(依賴)

    command(命令)

led.o : led.S
	arm-linux-gcc -g -o led.o -c led.S

-- 語法解析 : led.o 是目標, led.S 是依賴,  arm-linux-gcc -g -o led.o -c led.S 是命令;



(2) 通用規則


通用規則示例

%.o : %.c

    arm-linux-gcc -o %.o %.c

-- 解析 : 編譯 main.c 生成 main.o;




2. Makefile 目標




(1) 僞目標


Makefile 中的僞目標示例 : 僞目標 只有命令, 沒有依賴;

.PHONY: clean
clean:
	rm *.o led.elf led.bin
-- 僞目標標示 : ".PHONY: clean" 將 clean 聲明爲 僞目標;



(2) 最終目標



最終目標 : Makefile 默認執行 第一個目標, 第一個目標就是最終目標;




3. Makefile 變量



(1) 自定義變量


變量使用示例

-- 使用標量前

app1: app1.o func1.o func2.o
gcc app1.o func1.o func2.o -o app1
app2: app2.o func1.o func2.o
gcc app2.o func1.o func2.o -o app2
-- 定義變量 : obj=func1.o func2.o, 將該定義的變量應用於 Makefile;

obj=func1.o func2.o
app1: app1.o $(obj)
gcc app1.o $(obj) -o app1
app2: app2.o $(obj)
gcc app2.o $(obj) -o app2



(2) 系統定義變量


系統定義變量

-- $^ : 表明依賴的文件;

-- $@ : 表明目標;

-- $< : 表明第一個依賴文件;

-- 使用系統變量前

all: led.o 
	arm-linux-ld -Tled.lds -o led.elf led.o
	arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o led.o -c led.S
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin
-- 使用系統變量後

all: led.o 
	arm-linux-ld -Tled.lds -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o $@ -c $^
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin
-- 編譯運行 : 編譯結果與 不使用系統變量時的規則相同;




4. Makefile 技巧



(1) Makefile 去回顯


Makefile 去回顯

-- 回顯 : 執行編譯時, 會將命令打印到命令行中;


-- 去回顯 : 在命令前添加 "@" 符號;

all: led.o 
	@arm-linux-ld -Tled.lds -o led.elf $^
	@arm-linux-objcopy -O binary led.elf led.bin
	
led.o : led.S
	arm-linux-gcc -g -o $@ -c $^
	
.PHONY: clean
clean:
	rm *.o led.elf led.bin
-- 執行結果 : 此時就沒有上面兩條顯示了;



(2) Makefile 文件名稱修改


Makefile 文件名稱

-- 默認名稱 : make 工具默認尋找 "Makefile" 或者 "makefile" 文件, 若是沒有回報錯;


-- 指明 Makefile 文件make -f Makefile-ARM 命令;





四. 連接器腳本



1. 連接器腳本示例


可執行程序組成 : 代碼段, 數據段, bss 段; 連接器腳本就是配置這些段信息;


簡單的連接器腳本示例 : 

-- 代碼段 : .text 表示代碼段, * 表示全部文件, *(.text) 表示全部文件的代碼;

-- 數據段 : .data 表示數據段, * 表示全部文件, *(.data) 表示全部文件的數據段;

-- bss 段.bss 表示 bss 段, * 表示全部文件, *(.bss) 表示全部文件的 bss 段;

SECTIONS{
	.text :
	{
	*(.text)
	}

	.data :
	{
	*(.data)
	}

	.bss :
	{
	*(.bss)
	}
}



2. 設置起始連接器地址



設置連接器起始地址

-- 語法 : ". = 地址";

-- lds 腳本示例

SECTIONS{
	. =0x0;

	.text :
	{
	*(.text)
	}

	.data :
	{
	*(.data)
	}

	.bss :
	{
	*(.bss)
	}
}
-- 反編譯編譯後的 elf 文件 : "00000000 <_start>:" 表示從 0 地址開始;
[root@localhost 01_led]# arm-linux-objdump -D -S led.elf 

led.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
.text
.globl _start
#define VIC0_INT	0x71200000
#define VIC1_INT	0x71300000
-- 修改首地址後的腳本 : 將起始地址修改成 0x30008000;

SECTIONS{
	. =0x30008000;

	.text :
	{
	*(.text)
	}

	.data :
	{
	*(.data)
	}

	.bss :
	{
	*(.bss)
	}
}

-- 反編譯elf : 執行 arm-linux-objdump -D -S led.elf 命令, "30008000 <_start>:" 起始地址是 0x30008000;

[root@localhost 01_led]# arm-linux-objdump -D -S led.elf

led.elf:     file format elf32-littlearm

Disassembly of section .text:

30008000 <_start>:
.text
.globl _start
#define VIC0_INT	0x71200000
#define VIC1_INT	0x71300000 ... ...


地址對比

-- 連接器起始地址 0x000000


-- 連接器起始地址 0x30008000




3. 對齊設置


對齊範例 : . = ALIGN(4); 表示從當前開始 4 字節對齊;

SECTIONS{
	. =0x30008000;
	. = ALIGN(4);
	.text :
	{
	*(.text)
	}
	
	. = ALIGN(4);
	.data :
	{
	*(.data)
	}

	. = ALIGN(4);
	.bss :
	{
	*(.bss)
	}
}



4. 變量


變量示例 : 變量保存以後, 能夠再程序中用到變量;

-- 示例

SECTIONS{
	. =0x30008000;
	. = ALIGN(4);
	.text :
	{
	*(.text)
	}
	
	. = ALIGN(4);
	.data :
	{
	*(.data)
	}

	. = ALIGN(4);
	bss_start = . ;
	.bss :
	{
	*(.bss)
	}
	bss_end = . ;
}



5. 設置代碼段首文件


設置首文件

-- 語法 : start.o(.text);

-- 示例

SECTIONS{
	. =0x30008000;
	. = ALIGN(4);
	.text :
	{
	start.o(.text)
	*(.text)
	}
	
	. = ALIGN(4);
	.data :
	{
	*(.data)
	}

	. = ALIGN(4);
	bss_start = . ;
	.bss :
	{
	*(.bss)
	}
	bss_end = . ;
}



五. eclipse 在線調試



1. eclipse 集成開發環境示意圖



eclipse 集成開發環境示意圖

-- 硬件 : 開發板, JLink;

-- 軟件 : eclipse, GDB Server, JLink 軟件;





2. 準備工做



(1) 格式化 nand flash


格式化 nand flash :  注意必須格式化 NandFlash 不然會出現不可預知錯誤;



(2) 硬件鏈接


硬件鏈接 :  JLink 鏈接, 串口鏈接, 電源鏈接, 開發板 nand flash 啓動; 



(3) 安裝 JLink Windows 驅動


JLink Windows 驅動安裝 : 買 JLink 時會帶着這個安裝盤, 安裝 JLink Windows 驅動 才能夠調試成功, 不然會在 Windows 這一關被擋下 致使鏈接不成功;



(3) 安裝 gdb server


安裝 arm-linux-gdb-7.5.tar.gz

-- 解壓 : tar -xvzf arm-linux-gdb-7.5.tar.gz 命令;


-- 查看 build-all 腳本 : 能夠看到腳本執行流程是 解壓 gdb-7.5.tar.gz, 而後生成 Makefile文件, 以後進編譯安裝到 /opt/arm-linux-gdb 目錄下;

[root@localhost arm-linux-gdb-7.5]# cat build-all 
#/bin/sh

rm -fr gdb-7.5
rm -r /opt/arm-linux-gdb/

tar xvzf gdb-7.5.tar.gz
cd gdb-7.5

./configure --target=arm-linux --prefix=/opt/arm-linux-gdb/ -v

make && make install

cd /opt/arm-linux-gdb/
-- 進入 ddb 安裝目錄, 查看路徑


-- 配置環境變量 : 將 /etc/profile 中的環境變量刪除, 只在 ~/.bashrc 中配置;

export PATH=$PATH:/opt/arm-linux-gdb/bin/
export PATH=$PATH:/usr/local/arm/4.3.2/bin/
-- 環境變量順序 : 注意前面的環境變量覆蓋後面的, 交叉工具鏈中也有 arm-linu-gdb, 可是 /opt 下面的先配置, 所以事這個先生效;

-- 默認的 arm-linu-gdb : 是 7.5 版本的;


-- 交叉工具鏈中的 gdb : 6.8版本的, 沒法進行 在線調試;





(4) 安裝 JLink


安裝流程

-- 解壓文件 : JLink_Linux_V434a.tgz;

-- 進入cd JLink_Linux_V434a 目錄, 拷貝文件 : 拷貝 libjlinkarm.so.4 和 libjlinkarm.so.4.34.1 到 /usr/lib 目錄下 命令 cp -d libjlinkarm.so* /usr/lib -f, 拷貝 45-jlink.rules 到 /etc/udev/rules.d/ 下 命令 cp 45-jlink.rules /etc/udev/rules.d/;

[root@localhost ARM-tools]# tar -xvzf JLink_Linux_V434a.tgz 
JLink_Linux_V434a/
JLink_Linux_V434a/JLinkExe
JLink_Linux_V434a/libjlinkarm.so.4
JLink_Linux_V434a/start
JLink_Linux_V434a/JLinkGDBServer
JLink_Linux_V434a/libjlinkarm.so.4.34.1
JLink_Linux_V434a/README
JLink_Linux_V434a/45-jlink.rules
[root@localhost ARM-tools]# ls
arm-linux-gcc-4.3.2.tgz   dnw_usb.ko
arm-linux-gdb-7.5         eclipse-cpp-helios-SR2-linux-gtk.tar.gz
arm-linux-gdb-7.5.tar.gz  JLink_Linux_V434a
dnw                       JLink_Linux_V434a.tgz
[root@localhost ARM-tools]# cd JLink_Linux_V434a
[root@localhost JLink_Linux_V434a]# ls
45-jlink.rules  JLinkGDBServer    libjlinkarm.so.4.34.1  start
JLinkExe        libjlinkarm.so.4  README
[root@localhost JLink_Linux_V434a]# cp -d libjlinkarm.so* /usr/lib -f
[root@localhost JLink_Linux_V434a]# cp 45-jlink.rules /etc/udev/rules.d/


執行 JLinkGDBServer :

[root@localhost JLink_Linux_V434a]# ./JLinkGDBServer 
SEGGER J-Link GDB Server V4.34a

JLinkARM.dll V4.34a (DLL compiled Aug 31 2011 11:51:40)

Listening on TCP/IP port 2331

J-Link connected
Firmware: J-Link ARM V8 compiled Aug 24 2011 17:23:32
Hardware: V8.00
S/N: 17935099
Feature(s): RDI,FlashDL,FlashBP,JFlash

J-Link found 2 JTAG devices, Total IRLen = 5
JTAG ID: 0x07B76F0F (ARM11)




(5) 安裝 eclipse



安裝流程

-- 取消 默認 eclipse : 紅帽6.3中默認安裝了eclipse, 進入 /usr/bin 目錄, 將 eclipse 快捷方式改成 eclipse.bak, 若是須要使用這個 eclipse, 執行 eclipse.bak便可;

[root@localhost ~]# cd /usr/bin/
[root@localhost bin]# mv eclipse eclipse.bak
-- 開始啓動時會出錯 : 不用管, 在此啓動 eclipse 就會啓動成功;

[root@localhost eclipse]# ./eclipse 
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00b8f8c1, pid=11165, tid=3077863104
#
# JRE version: 6.0_24-b24
# Java VM: OpenJDK Client VM (20.0-b12 mixed mode linux-x86 )
# Derivative: IcedTea6 1.11.1
# Distribution: Red Hat Enterprise Linux Server release 6.2 (Santiago), package rhel-1.45.1.11.1.el6-i386
# Problematic frame:
# C  [UTF-16.so+0x8c1]  gconv+0x3c1
#
# An error report file with more information is saved as:
# /root/arm/ARM-tools/eclipse/hs_err_pid11165.log
#
# If you would like to submit a bug report, please include
# instructions how to reproduce the bug and visit:
#   http://icedtea.classpath.org/bugzilla
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
已放棄 (core dumped)
-- 安裝 CDT 插件 : 地址 http://opensource.zylin.com/zylincdt , 注意 三個都選擇;




(6) 工程配置


配置工程

-- 導入工程 : 選擇 菜單 "File" --> "New" --> "Makefile Project with Existing Code"


-- 取消自動編譯 : 菜單 "Project" --> "Build Automatically" 選項;

-- 清除編譯文件 : 選擇 "Project" --> "Clean ...", 就會清除 .o .elf .bin 文件;

-- 編譯文件 : "Project" --> "Build All" 選項, 同時 Console 中會有命令行輸出;





(7) Debug配置


Debug 配置

-- 設置Main 選項卡 : 雙擊 Zylin Embedded debug (Native), 建立 Degug, 設置工程名, 設置調試程序, 注意選擇 elf 格式的文件;


-- 設置 Debugger 選項卡 : 取消 Stop on startup at : main 選項, GDB debugger 程序選擇爲 arm-linux-gdb;


-- 設置初始化腳本 : 在 Commands 選項卡中設置 初始化腳本 , 注意下面的腳本是 ok6410 開發板的腳本, 其它開發板沒法使用;

# tiny6410_config
# connect to the J-Link gdb server
target remote localhost:2331
# Set JTAG speed to 30 kHz
monitor endian little
monitor speed 30
# Reset the target
monitor reset
monitor sleep 10
#
# CPU core initialization (to be done by user)
#
# Set the processor mode
monitor reg cpsr = 0xd3
#config MMU
#flush v3/v4 cache
monitor cp15 7, 7, 0, 0 = 0x0
#/* flush v4 TLB */
monitor cp15 8, 7, 0, 0 = 0x0
#disable MMU stuff and caches
monitor cp15 1, 0, 0, 0 =0x1002
#Peri port setup
monitor cp15 15, 2, 0, 4 = 0x70000013
#disable watchdog
monitor MemU32 0x7e004000  =  0x00000000
monitor sleep 10
#disable interrupt
monitor MemU32 0x71200014  =  0x00000000
monitor MemU32 0x71300014  =  0x00000000
monitor MemU32 0x7120000C  =  0x00000000
monitor MemU32 0x7130000C  =  0x00000000
monitor MemU32 0x71200F00  =  0x00000000
monitor MemU32 0x71300F00  =  0x00000000
#set clock 
monitor MemU32 0x7e00f900  =  0x0000801e
monitor MemU32 0x7e00f000  =  0x0000ffff
monitor MemU32 0x7e00f004  =  0x0000ffff
monitor MemU32 0x7e00f020  =  0x01043310
monitor MemU32 0x7e00f00C  =  0xc2150601
monitor MemU32 0x7e00f010  =  0xc2150601
monitor MemU32 0x7e00f024  =  0x00000003
monitor MemU32 0x7e00f014  =  0x00200102
monitor MemU32 0x7e00f018  =  0x00000000
monitor MemU32 0x7e00f01C  =  0x14000007
#config sdram
monitor MemU32 0x7e00f120  =  0x00000008
monitor MemU32 0x7e001004  =  0x00000004
monitor MemU32 0x7e001010  =  0x0000040f
monitor MemU32 0x7e001014  =  0x00000006
monitor MemU32 0x7e001018  =  0x00000001
monitor MemU32 0x7e00101c  =  0x00000002
monitor MemU32 0x7e001020  =  0x00000006
monitor MemU32 0x7e001024  =  0x0000000a
monitor MemU32 0x7e001028  =  0x0000000c
monitor MemU32 0x7e00102c  =  0x0000018f
monitor MemU32 0x7e001030  =  0x0000000c
monitor MemU32 0x7e001034  =  0x00000002
monitor MemU32 0x7e001038  =  0x00000002
monitor MemU32 0x7e00103c  =  0x00000002
monitor MemU32 0x7e001040  =  0x00000002
monitor MemU32 0x7e001044  =  0x00000013
monitor MemU32 0x7e001048  =  0x00000013
monitor MemU32 0x7e00100C  =  0x00010012
monitor MemU32 0x7e00104C  =  0x00000b45
monitor MemU32 0x7e001200  =  0x000150f8
monitor MemU32 0x7e001304  =  0x00000000
monitor MemU32 0x7e001008  =  0x000c0000
monitor MemU32 0x7e001008  =  0x00000000
monitor MemU32 0x7e001008  =  0x00040000
monitor MemU32 0x7e001008  =  0x00040000
monitor MemU32 0x7e001008  =  0x000a0000
monitor MemU32 0x7e001008  =  0x00080032
monitor MemU32 0x7e001004  =  0x00000000
# Setup GDB for faster downloads
#set remote memory-write-packet-size 1024
set remote memory-write-packet-size 4096
set remote memory-write-packet-size fixed
monitor speed 12000
break _start
load


-- Debug 調試 : 執行 debug 調試, 再彈出的對話框中點擊 yes;

   

-- 此時能夠單步調試




.

做者 : 韓曙亮

博客地址 : http://blog.csdn.net/shulianghan/article/details/42239705 

參考博客 【嵌入式開發】嵌入式 開發環境 (遠程登陸 | 文件共享 | NFS TFTP 服務器 | 串口鏈接 | Win8.1 + RedHat Enterprise 6.3 + Vmware11)

相關文章
相關標籤/搜索