微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么此链接描述文件会生成一对一地址?

如何解决为什么此链接描述文件会生成一对一地址?

我正在为 ARM Cortex-M0 微控制器(特别是作为 STM32 discovery 开发板一部分的 STM32F072B)编写一些固件代码

我的链接器脚本没有做任何特别的事情,它只是填写向量表,然后包含我代码中的所有文本和数据部分:

OUTPUT_FORMAT("elf32-littlearm")

MEMORY {
    ROM (rx) : ORIGIN = 0x00000000,LENGTH = 16K
    FLASH (r) : ORIGIN = 0x08000000,LENGTH = 64K
    RAM (rw)  : ORIGIN = 0x20000000,LENGTH = 16K
}

ENTRY(_start)

PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));


SECTIONS {

    .vector_table : {
        LONG(__stack_top);                  /* 00 */
        LONG(_start);                       /* 04 */  
        LONG(dummy_isr);                    /* 08 */
        LONG(dummy_isr);                    /* 0C */
        LONG(dummy_isr);                    /* 10 */
        LONG(dummy_isr);                    /* 14 */
        LONG(dummy_isr);                    /* 18 */
        LONG(dummy_isr);                    /* 1C */
        LONG(dummy_isr);                    /* 20 */
        LONG(dummy_isr);                    /* 24 */
        LONG(dummy_isr);                    /* 28 */
        LONG(dummy_isr);                    /* 2C */
        LONG(dummy_isr);                    /* 30 */
        LONG(dummy_isr);                    /* 34 */
        LONG(dummy_isr);                    /* 38 */
        LONG(dummy_isr);                    /* 3C */
        LONG(dummy_isr);                    /* 40 */
        LONG(dummy_isr);                    /* 44 */
        LONG(dummy_isr);                    /* 48 */
        LONG(dummy_isr);                    /* 4C */
        LONG(dummy_isr);                    /* 50 */
        LONG(dummy_isr);                    /* 54 */
        LONG(dummy_isr);                    /* 58 */
        LONG(dummy_isr);                    /* 5C */
        LONG(dummy_isr);                    /* 60 */
        LONG(dummy_isr);                    /* 64 */
        LONG(dummy_isr);                    /* 68 */
        LONG(dummy_isr);                    /* 6C */
        LONG(dummy_isr);                    /* 70 */
        LONG(dummy_isr);                    /* 74 */
        LONG(dummy_isr);                    /* 78 */
        LONG(dummy_isr);                    /* 7C */
        LONG(dummy_isr);                    /* 80 */
        LONG(dummy_isr);                    /* 84 */
        LONG(dummy_isr);                    /* 88 */
        LONG(dummy_isr);                    /* 8C */
        LONG(dummy_isr);                    /* 90 */
        LONG(dummy_isr);                    /* 94 */
        LONG(dummy_isr);                    /* 98 */
        LONG(dummy_isr);                    /* 9C */
        LONG(dummy_isr);                    /* A0 */
        LONG(dummy_isr);                    /* A4 */
        LONG(dummy_isr);                    /* A8 */
        LONG(dummy_isr);                    /* AC */
        LONG(dummy_isr);                    /* B0 */
        LONG(dummy_isr);                    /* B4 */
        LONG(dummy_isr);                    /* B8 */
        LONG(dummy_isr);                    /* BC */
    } > ROM AT > FLASH
    
    .text : {
        *(.text*)
    } > ROM AT > FLASH

    .rodata : {
        *(.rodata*)
        *(.data.rel.ro)
    } > FLASH

    .bss (NOLOAD) : {
        *(.bss*)
        *(COMMON)
    } > RAM

    .data : {
        *(.data*)
    } > RAM

    .ARM.exidx : {
       *(.ARM.exidx)
    } > FLASH

}

当我构建和链接一个 ELF 文件并转储符号时,我注意到 .vector_table 部分中结束的地址以及 ELF 入口点都相差一个

[shell]$ llvm-objdump --syms zig-cache/bin/main-flash 

zig-cache/bin/main-flash:       file format elf32-littlearm

SYMBOL TABLE:
00000000 l    df *ABS*  00000000 main-flash
0000013c l       .text  00000000 $d.1
000000c0 l       .text  00000000 $t.0
000000c4 g     F .text  00000088 _start
000000c0 g     F .text  00000002 dummy_isr
20004000 g       *ABS*  00000000 __stack_top

[shell]$ llvm-objdump --full-contents --section=.vector_table zig-cache/bin/main-flash 

zig-cache/bin/main-flash:       file format elf32-littlearm

Contents of section .vector_table:
 0000 00400020 c5000000 c1000000 c1000000  .@. ............
 0010 c1000000 c1000000 c1000000 c1000000  ................
 0020 c1000000 c1000000 c1000000 c1000000  ................
 0030 c1000000 c1000000 c1000000 c1000000  ................
 0040 c1000000 c1000000 c1000000 c1000000  ................
 0050 c1000000 c1000000 c1000000 c1000000  ................
 0060 c1000000 c1000000 c1000000 c1000000  ................
 0070 c1000000 c1000000 c1000000 c1000000  ................
 0080 c1000000 c1000000 c1000000 c1000000  ................
 0090 c1000000 c1000000 c1000000 c1000000  ................
 00a0 c1000000 c1000000 c1000000 c1000000  ................
 00b0 c1000000 c1000000 c1000000 c1000000  ................
[shell]$ readelf -h zig-cache/bin/main-flash 
ELF Header:
...
  Entry point address:               0xc5

符号表在 0xC4 处显示 _start,而在链接描述文件中定义为 _start 的 ELF 入口点设置为 0xC5。同样,写入向量表的dummy_isr的地址也是off-by-1(dummy_isr符号定义为0xC0,而0xC1由链接器写入向量表)。 .text 的反汇编确认 _dummy_isr_start 分别从 0xC0 和 0xC4 开始,因此链接器写入的地址是错误的:

[shell]$ llvm-objdump --disassemble --section=.text zig-cache/bin/main-flash 
                                                               
zig-cache/bin/main-flash:       file format elf32-littlearm
                                                               

disassembly of section .text:
                                                               
000000c0 <dummy_isr>:                                          
      c0: fe e7         b       #-4 <dummy_isr>   
      c2: c0 46         mov     r8,r8            
                               
000000c4 <_start>:
      c4: 82 b0         sub     sp,#8
      c6: 01 23         movs    r3,#1
      c8: d8 04         lsls    r0,r3,#19
      ca: 1c 49         ldr     r1,[pc,#112]
...

0xC1 和 0xC5 甚至不是有效指令的地址,它们都在一条指令的中间。什么可能导致这种差异?

解决方法

这称为“互通地址”。

地址的最低有效位指示目标指令是 ARM (0) 还是 Thumb (1)。获取的地址始终将 LSB 设置为零。

由于此平台仅在 Thumb 模式下工作,因此与 BX 和 BLX 指令一起使用的所有向量地址和地址必须是奇数(X 表示 (ex)change 指令集)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。