【嵌入式开发】 嵌入式开发工具简介 (裸板调试示例 | 交叉工具链 | Makefile | 链接器脚本 | eclipse JLink 调试环境)(二)

简介: 【嵌入式开发】 嵌入式开发工具简介 (裸板调试示例 | 交叉工具链 | Makefile | 链接器脚本 | eclipse JLink 调试环境)(二)

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 文件;

image.png



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

image.png



-- 链接器命令格式 : -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 表示输出二进制格式;


image.png









三. 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

-- 编译运行 : 编译结果与 不使用系统变量时的规则相同;

image.png








4. Makefile 技巧




(1) Makefile 去回显


Makefile 去回显 :


-- 回显 : 执行编译时, 会将命令打印到命令行中;


image.png


-- 去回显 : 在命令前添加 "@" 符号;



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

-- 执行结果 : 此时就没有上面两条显示了;



image.png




(2) Makefile 文件名称修改


Makefile 文件名称 :


-- 默认名称 : make 工具默认寻找 "Makefile" 或者 "makefile" 文件, 如果没有回报错;

image.png



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

image.png










四. 链接器脚本





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 :

image.png



-- 链接器起始地址 0x30008000 :

image.png




目录
相关文章
|
6月前
|
Java Android开发
在Eclipse环境下调试Java程序
在Eclipse环境下调试Java程序
71 1
|
Java 关系型数据库 MySQL
SSM度假村管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
SSM 度假村管理系统是一套完善的信息系统,结合SSM框架完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 前段主要技术html div js 后端主要技术 SSM框架 java jdbc 数据库 mysql 开发工具 eclipse JDK1.8 TOMCAT 8.5
54 0
|
4月前
|
存储 Oracle Java
Java面试题:描述如何使用Eclipse或IntelliJ IDEA进行Java开发?
Java面试题:描述如何使用Eclipse或IntelliJ IDEA进行Java开发?
45 0
|
5月前
|
开发工具 Android开发 git
合作开发(Eclipse+git +码云)
合作开发(Eclipse+git +码云)
66 0
|
6月前
|
Java 关系型数据库 BI
基于Java Swing 开发的网吧管理系统【eclipse和idea两个版本运行源码】
基于Java Swing 开发的网吧管理系统【eclipse和idea两个版本运行源码】
114 0
|
6月前
|
设计模式 前端开发 Java
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
86 0
|
6月前
|
Android开发
Eclipse工具使用技巧
Eclipse工具使用技巧
|
Java 关系型数据库 MySQL
SSM宾馆客房管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
SSM 宾馆客房管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 前段主要技术 bootstrap.css jquery 后端主要技术 SSM 数据库 mysql 开发工具 eclipse JDK1.8 TOMCAT 8.5
62 0
SSM宾馆客房管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
|
12月前
|
Java 关系型数据库 Apache
Apache Maven简介&安装及系统坏境配置&eclipse配置Apache Maven---详细介绍
Apache Maven简介&安装及系统坏境配置&eclipse配置Apache Maven---详细介绍
142 0
|
Java 关系型数据库 MySQL
SSM培训报名管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
SSM 培训报名管理系统是一套完善的信息系统,结合SSM框架完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 前段主要技术html div js 后端主要技术 SSM框架 java jdbc 数据库 mysql 开发工具 eclipse JDK1.8 TOMCAT 8.5
53 0

推荐镜像

更多