ARM Cortex-M4 上链接描述文件中自定义 .rawdata 部分的数据完整性问题

问题描述 投票:0回答:1

我正在使用 ARM Cortex-M4 处理器(特别是

STM32F4
微控制器)开发一个嵌入式项目,并且遇到了与链接器脚本中定义的内存部分相关的特殊问题。我正在使用
arm-none-eabi-gcc
工具链进行编译。

我有一个二进制文件,我想将其包含在我的固件中。我在汇编文件中创建了一个自定义部分 (

.rawdata
) 以包含此二进制文件,并且我修改了
linker script
以将此部分放入
Flash
内存中。但是,我在运行时面临 .rawdata 部分中数据完整性的问题。

当我将

.rawdata
部分放置在
.data
部分或我的
.text
中的
linker script
部分时,一切都会按预期工作:数据在内存中正确分配,并且实际数据正确存储。我可以在运行时访问和打印数据,没有任何问题。

但是,当我尝试创建一个独立的

.rawdata
部分(在
.data
之外)或将其放置在
.text
部分内时,数据似乎已分配,但内容不是我所期望的。在运行时,当我打印
.rawdata
部分的内容时,我得到不正确的值(与原始
.bin
内容不匹配)。 有趣的是,当我使用
.elf
检查
arm-none-eabi-objdump
文件时,
.rawdata
部分似乎包含正确的数据。这种差异仅在运行时发生。

链接器脚本片段:

ld
.rawdata :
{
  . = ALIGN(4);
  _mstart = .;
  KEEP(*(.rawdata))
  . = ALIGN(4);
  _mend = .;
} >FLASH

为什么将

.rawdata
部分放置在
.data
部分内可以正常工作,但将其创建为独立部分会导致运行时数据不正确? 对于 ARM Cortex-M4 处理器的链接器脚本中的自定义部分,是否缺少特定的注意事项或配置?

.rawdata
部分的数据在 .data 部分之外定义时,如何确保其数据在运行时保持完整?

任何有关如何解决此问题的见解或建议将不胜感激。预先感谢您的帮助!

如果我检查使用

arm-none-eabi-objdump -h -j .rawdata blink.elf
arm-none-eabi-objdump -s -j .rawdata blink.elf


blink.elf:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  1 .rawdata      0000003c  080001c8  080001c8  000071dc  2**0
                  CONTENTS, READONLY

blink.elf:     file format elf32-littlearm

Contents of section .rawdata:
 80001c8 cdcccc3d cdcc4c3e 9a99993e cdcccc3e  ...=..L>...>...>
 80001d8 0000003f 9a99193f 3333333f cdcc4c3f  ...?...?333?..L?
 80001e8 6666663f 0000803f cdcc8c3f 9a99993f  fff?...?...?...?
 80001f8 6666a63f 3333b33f 0000c03f           ff.?33.?...?    

这是应该加载的正确数据。

但是,如果在运行时我检查使用 USART 打印该内存区域内的内容,我会得到:

data size: 60 bytes
Start address: 0x80001c8
End address: 0x8000204
00000000
00000000
3f501eb4
bfe008ee
3d600962
416277e1
c6ffe8d3
3c201ffe
40c1e8d1
41428902
c6004342
4161df76
c2000560
4161a8f3
c2000560

其中地址与上面相同,但内存中的内容不同。

相反, 如果我将

.rawdata
放在
.text
.data
部分内,我会得到与应有的相同的内存内容。

gcc linker arm stm32 linker-scripts
1个回答
0
投票

这就是你看到的吗?

.globl _start
.thumb

_start:
.word 0x20001000
.word reset


.thumb_func
reset:
    b .

.align
.word 0x88888888
.word _mstart
.word _mend
.word 0x88888888

.section .data
.word 0x12341234

.section .rawdata
.word 0x11223344

.section .bss
.word 0

.section .rodata
.word 0x22222222

并用

进行测试
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -T so.ld so.o -o so.elf
arm-none-eabi-objdump -D so.elf
arm-none-eabi-readelf -a so.elf
arm-none-eabi-objcopy -O binary so.elf so.bin
hexdump -C so.bin
arm-none-eabi-objcopy -O srec --srec-forceS3 so.elf so.srec
cat so.srec

并且可以清楚地看到问题

arm-none-eabi-objdump -D so.elf

so.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000009    stmdaeq r0, {r0, r3}

08000008 <reset>:
 8000008:   e7fe        b.n 8000008 <reset>
 800000a:   46c0        nop         ; (mov r8, r8)
 800000c:   88888888    stmhi   r8, {r3, r7, fp, pc}
 8000010:   08000020    stmdaeq r0, {r5}
 8000014:   08000024    stmdaeq r0, {r2, r5}
 8000018:   88888888    stmhi   r8, {r3, r7, fp, pc}

Disassembly of section .bss:

20000000 <.bss>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <.data>:
20000004:   12341234    eorsne  r1, r4, #52, 4  ; 0x40000003

Disassembly of section .rawdata:

08000020 <_mstart>:
 8000020:   11223344            ; <UNDEFINED> instruction: 0x11223344

Disassembly of section .rodata:

08000020 <.rodata>:
 8000020:   22222222    eorcs   r2, r2, #536870914  ; 0x20000002

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        08000000 010000 00001c 00  AX  0   0  4
  [ 2] .bss              NOBITS          20000000 030000 000004 00  WA  0   0  1
  [ 3] .data             PROGBITS        20000004 020004 000004 00  WA  0   0  1
  [ 4] .rawdata          PROGBITS        08000020 020024 000004 00      0   0  1
  [ 5] .rodata           PROGBITS        08000020 020020 000004 00   A  0   0  1



Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x08000000 0x08000000 0x0001c 0x0001c R E 0x10000
  LOAD           0x020004 0x20000004 0x0800001c 0x00004 0x00004 RW  0x10000
  LOAD           0x020020 0x08000020 0x08000020 0x00004 0x00004 R   0x10000
  LOAD           0x000000 0x20000000 0x20000000 0x00000 0x00004 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data 
   02     .rodata 
   03     .bss 




00000000  00 10 00 20 09 00 00 08  fe e7 c0 46 88 88 88 88  |... .......F....|
00000010  20 00 00 08 24 00 00 08  88 88 88 88 34 12 34 12  | ...$.......4.4.|
00000020  22 22 22 22                                       |""""|
00000024



S00A0000736F2E7372656338
S315080000000010002009000008FEE7C0468888888896
S3110800001020000008240000088888888862
S3090800001C3412341246
S309080000202222222246
S70508000000F2

_mstart 位于 0x0800020,但 .rodata 也在那里...并且 .rawdata 现在不在该转储中,它不转储可能没问题,但也许不是。

理想情况下,名称是任意的,请记住这一点

.one   : { *(.two*)   } > rom

.two 是创建对象的工具的名称,一些名称。 .one 是您要使用链接器更改/转换/输出的名称。

可惜这个世界不是我想要的任何名字。有特殊的名字。如果这就是你发现的,我怀疑这就是你着陆的地方。

或许和这个有关

secname 必须满足您的输出格式的限制。在仅支持有限数量的部分的格式中,例如 a.out,名称必须是该格式支持的名称之一(例如,a.out 只允许 .text、.data 或 .bss)。

使用添加或保留部分到 objcopy 不会改变/帮助。

.text :
{
  . = ALIGN(4);
  _mstart = .;
  KEEP(*(.rawdata))
  . = ALIGN(4);
  _mend = .;
} > rom

00000000  00 10 00 20 09 00 00 08  fe e7 c0 46 88 88 88 88  |... .......F....|
00000010  1c 00 00 08 20 00 00 08  88 88 88 88 44 33 22 11  |.... .......D3".|
00000020  34 12 34 12 22 22 22 22                           |4.4.""""|
00000028


S00A0000736F2E7372656338
S315080000000010002009000008FEE7C0468888888896
S315080000101C000008200000088888888844332211BC
S309080000203412341242
S309080000242222222242
S70508000000F2

我们看到数据就在那里,在正确的位置,并且开始和结束都是正确的。

.data :
{
  . = ALIGN(4);
  _mstart = .;
  KEEP(*(.rawdata))
  . = ALIGN(4);
  _mend = .;
} > rom


00000000  00 10 00 20 09 00 00 08  fe e7 c0 46 88 88 88 88  |... .......F....|
00000010  20 00 00 08 24 00 00 08  88 88 88 88 34 12 34 12  | ...$.......4.4.|
00000020  44 33 22 11 22 22 22 22                           |D3".""""|
00000028

也有效。

如果您使用 openocd 读取 ELF 文件,那么现在它就变成了该工具解释 elf 和可加载部分的方式。精灵没有以我期望加载的方式标记此部分。

这样的事情也没有帮助。

fun (L) : ORIGIN = 0x08001000, LENGTH = 0x1000

...

.rawdata :
{
  . = ALIGN(4);
  _mstart = .;
  KEEP(*(.rawdata))
  . = ALIGN(4);
  _mend = .;
} > fun

使用 .text 或 .data (或 .rodata 也可以)作为输出节名称似乎可以毫不费力地工作。我会采取这条路径,除非您用来读取 elf 文件的工具专门寻找您正在创建的部分。如果这就是您想要一个新的部分名称(在链接的输出上)的原因,那么只需在您的 elf 阅读工具中添加该支持即可。如果您只想有一个用于链接目的的新部分,那么我会将输出部分名称作为基础知识之一。如果你想要两者兼而有之,那么我会制作一个 elf 工具来修改 elf 以使其可加载或任何 openocd 想要的东西,但这只是我,因为我可以在比我能弄清楚是否有某种工具更短的时间内制作那个 elf 工具存在以及如何让它完成这项任务。 YMMV.

我认为您遇到的情况是,虽然我们希望工具是通用的,但某些部分名称是已知的且特殊的并且......只是工作。

© www.soinside.com 2019 - 2024. All rights reserved.