在linikers的意义上,可加载对微控制器意味着什么

时间:2017-10-07 01:08:25

标签: gcc linker arm cortex-m

我试图熟悉ARM Cortex-M4微控制器中的链接和启动过程。浏览链接器脚本几乎所有部分都标记为可加载。

起初我认为这意味着它会从闪存复制到RAM,但后来我才知道这样做是以不同的方式处理的。那么flash中的一个部分可以加载是什么意思呢?它已经加载并从闪存中的位置运行了吗?另外,我指的是包含说明的章节。

在这种情况下可加载是否意味着调试器加载到设备中?

1 个答案:

答案 0 :(得分:2)

一个功能齐全的皮质m程序

flash.s

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang

.thumb_func
hang:   b .
.align

.thumb_func
.globl dummy
dummy:
    bx lr

so.c

void dummy ( unsigned int );
int notmain ( void )
{
    unsigned int ra;

    for(ra=0;ra<10;ra++) dummy(ra);
    return(0);
}

flash.ld     记忆     {         rom:ORIGIN = 0x00000000,LENGTH = 0x1000         ram:ORIGIN = 0x20000000,LENGTH = 0x1000     }

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

构建

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -c so.c -o so.o
arm-none-eabi-ld -o so.elf -T flash.ld flash.o so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary

(可以使用cortex-m4起作用)

so.list

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   00000011    andeq   r0, r0, r1, lsl r0
   8:   00000017    andeq   r0, r0, r7, lsl r0
   c:   00000017    andeq   r0, r0, r7, lsl r0

00000010 <reset>:
  10:   f000 f804   bl  1c <notmain>
  14:   e7ff        b.n 16 <hang>

00000016 <hang>:
  16:   e7fe        b.n 16 <hang>

00000018 <dummy>:
  18:   4770        bx  lr
  1a:   46c0        nop         ; (mov r8, r8)

0000001c <notmain>:
  1c:   b510        push    {r4, lr}
  1e:   2400        movs    r4, #0
  20:   0020        movs    r0, r4
  22:   3401        adds    r4, #1
  24:   f7ff fff8   bl  18 <dummy>
  28:   2c0a        cmp r4, #10
  2a:   d1f9        bne.n   20 <notmain+0x4>
  2c:   2000        movs    r0, #0
  2e:   bc10        pop {r4}
  30:   bc02        pop {r1}
  32:   4708        bx  r1

是一个不太复杂的链接器脚本和程序,精灵有更少的东西

readelf的一部分

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        00000000 010000 000034 00  AX  0   0  4
  [ 2] .ARM.attributes   ARM_ATTRIBUTES  00000000 010034 00002d 00      0   0  1
  [ 3] .comment          PROGBITS        00000000 010061 000011 01  MS  0   0  1
  [ 4] .symtab           SYMTAB          00000000 010074 0000f0 10      5  12  4
  [ 5] .strtab           STRTAB          00000000 010164 00003d 00      0   0  1
  [ 6] .shstrtab         STRTAB          00000000 0101a1 00003a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x00000000 0x00000000 0x00034 0x00034 R E 0x10000

hexdump -C so.bin

00000000  00 10 00 20 11 00 00 00  17 00 00 00 17 00 00 00  |... ............|
00000010  00 f0 04 f8 ff e7 fe e7  70 47 c0 46 10 b5 00 24  |........pG.F...$|
00000020  20 00 01 34 ff f7 f8 ff  0a 2c f9 d1 00 20 10 bc  | ..4.....,... ..|
00000030  02 bc 08 47                                       |...G|
00000034

a&#34;二进制&#34;有许多种类,它是一个不幸的命名不好的术语,因为它是如此令人困惑。您在上面的反汇编中看到的所有内容都是程序运行所必需的,这是它的真正二进制部分,必须在需要加载运行的任何地方加载它。如果在操作系统上,则操作系统读取elf文件,使用其地址/偏移量提取可加载部分,并在入口点启动之前将它们加载到内存中。利用已经具有elf文件格式的工具,我们可以重复使用其中的一些用于微控制器,我们不能/通常不使用入口点,因为这没有意义,我们必须使向量/入口点匹配硬件需要,在这种情况下是一个向量表。

来自objcopy的hexdump还显示了我们必须让处理器可见的部分,以便程序运行,或加载到地址/内存空间(在这种情况下,闪存位于内存或地址空间)。

但&#34;二进制&#34;文件,elf还包含调试符号,以防您想要启动调试器,在工具链命令行中添加更多选项,您可以获得有关这些项在源代码文件中的位置的更多信息,这样您在某些情况下可以看到单步执行代码时的高级语言。那些不是可加载的部分,它们是程序的描述或只是帮助,它们不是机器代码,也不是处理器执行程序所需的数据,所以它们不需要加载到内存空间。

另一个&#34;二进制&#34;文件格式

arm-none-eabi-objcopy so.elf -O ihex so.hex
cat so.hex 
:100000000010002011000000170000001700000081
:1000100000F004F8FFE7FEE77047C04610B5002483
:1000200020000134FFF7F8FF0A2CF9D1002010BCA2
:0400300002BC0847BF
:00000001FF

它有一些额外的信息,但几乎所有这些都是我们必须加载到地址空间以供程序运行的部分

另一种二进制文件格式

S00A0000736F2E7372656338
S1130000001000201100000017000000170000007D
S113001000F004F8FFE7FEE77047C04610B500247F
S113002020000134FFF7F8FF0A2CF9D1002010BC9E
S107003002BC0847BB
S9030000FC

也大部分是节目。

elf只是另一种文件格式(非常受gnu工具欢迎,但仍然只是另一种文件格式),它包含所需的机器代码和数据以及一堆其他东西,机器代码和数据是我们必须加载的如果这是一个操作系统,或者我们理想地加载到微控制器的闪存中,但是并非所有微控制器都是相同的,那么只有基于ram的内存并且在枚举期间通过usb下载程序(进入ram)。和其他解决方案,或者如果调试你可能有物品加载到ram取决于mcu和工具,虽然这不是如何启动,所以这不是一个很好的二进制文件。

如果您认为需要将.bss归零并拥有任何.data,那么您需要其他信息,.bss的偏移量和大小以及.data的偏移量和内容,然后引导程序将这些项置零并复制,以及您需要在非易失性闪存/ ROM中获取该信息,这只是运行程序所需的机器代码和数据所需的更多数据。如果你让其他人为你编写代码,那么可能有定制的链接器脚本和引导代码,它们允许你只有.data项目并在gui上按下一个构建按钮,当你的入口点(主要的) ()按惯例和/或标准)开始执行或代表C入口点的高级代码的代码。