【问题标题】:.data LMA overlapps .data VMA addresses.data LMA 与 .data VMA 地址重叠
【发布时间】:2011-09-23 11:59:27
【问题描述】:

我对链接器脚本概念很陌生。 我遇到了一些奇怪的问题。

这些部分似乎没有 VMA 的正确地址。

例如,如果我们查看在 LMA+size 中提供的 VMA 的 .data 部分。 (这意味着在启动过程中,一旦我将数据从 LMA 复制到 VMA,LMA 地址的最后一个字节将被覆盖)

这是结果的样子,查看 .data 你会明白我的意思:

部分: Idx 名称大小 VMA LMA 文件关闭 Algn 0 .rcw 00000008 20000000 20000000 00010000 2**0 内容、分配、加载、只读、代码 1 .init 00000628 20000008 20000008 00010008 2**0 内容、分配、加载、只读、代码 2.文本 000177f8 20000630 20000630 00010630 2**4 内容、分配、加载、只读、代码 3 .flash_data 00000010 20017e28 20017e28 00027e28 2**0 内容、分配、加载、只读、代码 4 .rodata 00000ec0 20017e38 20017e38 00027e38 2**4 内容、分配、加载、只读、数据 5 .xcptn 000008e8 20019000 20019000 00029000 2**4 内容、分配、加载、只读、代码 6 .extram 00002080 2001a000 200198e8 0002a000 2**13 内容、分配、加载、数据 7.数据000008f0 2001c080 2001b968 0002c080 2**3 内容、分配、加载、数据 8 .得到 00000010 2001c970 2001c258 0002c970 2**2 内容、分配、加载、代码 9 .got2 00000220 2001c980 2001c268 0002c980 2**2 内容、分配、加载、数据 10.sdata 00000038 2001cba0 2001c488 0002cba0 2**2 内容、分配、加载、数据 11 .sbss 00000088 2001cbd8 2001c4c0 0002cbd8 2**2 分配 12 .bss 0000bbbc 2001cc60 2001c548 0002cbd8 2**2 分配 13 .isrvectbl 00000d88 2002881c 20028104 0002cbd8 2**2 分配 14 .debug_aranges 00001618 00000000 00000000 0002cbd8 2**3 内容,只读,调试 15 .debug_pubnames 00002843 00000000 00000000 0002e1f0 2**0 内容,只读,调试 16 .debug_info 0003f23a 00000000 00000000 00030a33 2**0 内容,只读,调试 17 .debug_abbrev 00009c89 00000000 00000000 0006fc6d 2**0 内容,只读,调试 18 .debug_line 0000ae64 00000000 00000000 000798f6 2**0 内容,只读,调试 19 .debug_frame 00003bb8 00000000 00000000 0008475c 2**2 内容,只读,调试 20 .debug_str 00007b24 00000000 00000000 00088314 2**0 内容,只读,调试 21 .debug_loc 00015465 00000000 00000000 0008fe38 2**0 内容,只读,调试 22 .debug_ranges 00001768 00000000 00000000 000a52a0 2**3 内容,只读,调试 23 .comment 00000750 00000000 00000000 000a6a08 2**0 内容,只读 24 .gnu.attributes 00000012 00000000 00000000 000a7158 2**0 内容,只读

以下 ld 脚本是提供给我的:

条目(__开始) /* ****************************************************** *************** * PE_MPC5554_rom.ld * MPC5554 的 GNU powerpc-eabispe 链接器脚本 * 默认情况下,此应用程序在内部闪存、SRAM 和缓存中运行 * C。 2005,P&E 微电脑系统公司 * 修订作者 日期 变更说明 * --- ----------- ---------- --------- * 0.1 C.Baker FSL 19/Jul/06 更改了内存布局、堆栈 * 变量和文件名。 * 0.2 C.Baker FSL 21/Sep/06 更改了缓存地址中的堆栈。 ****************************************************** *************** */ 记忆 { /* 32M 外部 SRAM */ ext_ram : org = 0x20000000, len = 0x02000000 /* G3 板上 32M */ /* 内部闪存 RCW */ /* MPC5567 2M 内部闪存,但减去两个 128K 块供仿真 eeprom 使用。 */ /* 但减去一个 128K 块供 BAM 使用。 */ /* MPC5567 80K 内部 SRAM */ flash_rcw : org = 0x00000000, len = 0x8 int_flash : org = 0x00000008, len = 0x001BFFF8 int_sram : org = 0x40000000, len = 0x14000 /* e4_flash 为高地址空间分区 9 中的模拟 eeprom 保留。 */ e4_flash : org = 0x001C0000, len = 0x40000 } /* 应用程序的性能可能会通过锁定来提高 */ /* 将堆栈放入缓存。但是,因为这会使调试变得复杂(例如,*/ /* 函数参数在 GDB 中不可见)它只适用于 */ /* 生产代码,不在开发期间。在 */ 中将 STACK_IN_CACHE 设置为 1 /* 应用程序的“config.inc”将堆栈锁定到缓存中。否则,设置 */ /* STACK_IN_CACHE 为 0,并且栈将被放置在顶部 */ /* 内部 RAM。 */ /* 堆栈地址参数 */ /* __SP_END = 定义(STACK_IN_CACHE)? 0x40040000:0x40013000; */ __SP_END = 0x40013000; __STACK_SIZE = 0x1000; __SP_INIT = __SP_END + __STACK_SIZE; /* 可选地用堆的地址定义这个变量 __heap_start = __SP_END; */ /************************************************* ***************/ 部分 { .rcw: { 保持(*(.rcw)) } > ext_ram /* CRT0 启动代码 */ .pecrt0 对齐(8): { *(.pecrt0) PEFILL = .; . =对齐(8); } > ext_ram .interp 对齐(8): { *(.interp) . =对齐(8); } > ext_ram .hash 对齐(8): { *(.hash) . =对齐(8); } > ext_ram .dynsym 对齐(8): { *(.dynsym) . =对齐(8); } > ext_ram .dynstr 对齐(8): { *(.dynstr) . =对齐(8); } > ext_ram .rela.dyn 对齐(8): { *(.rela.init) *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) *(.rela.fini) *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) *(.rela.ctors) *(.rela.dtors) *(.rela.got) *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) . =对齐(8); } > ext_ram .init 对齐(8): { 提供 (__init = .); 保持(*(.init)) . =对齐(8); } > ext_ram .text 对齐(8): { *(。文本) *(。文本。*) *(.gnu.warning) *(.gnu.linkonce.t*) __eabi = (.); /*PE*/ 长(0x4E800020); . =对齐(8); } > ext_ram .fini 对齐(8): { /*提供 (__fini = .);*/ 保持(*(.fini)) . =对齐(8); } > ext_ram .flash_data 对齐(8): { 保持(*(.flash_data)) . =对齐(8); } > ext_ram .rodata 对齐(8): { . =对齐(8); *(.rodata) *(.rodata.*) *(.gnu.linkonce.r*) . =对齐(8); } > ext_ram .rodata1 对齐(8): { *(.rodata1) . =对齐(8); } > ext_ram .PPC.EMB.apuinfo 对齐(8): { *(.PPC.EMB.apuinfo) . =对齐(8); } > ext_ram AT > ext_ram /* 软件向量模式的 ISR 表 */ .isrvectbl 对齐(0x800):ONLY_IF_RO { 保持(*(.isrvectbl)) } > ext_ram 提供 (__EXCEPT_START__ = .); /* IVOR4Handler */ .xcptn 对齐(8): { 保持(*(.xcptn)) . =对齐(8); } > ext_ram 提供 (__EXCEPT_END__ = .); 文本 = .; _etext = .; __etext = .; /************************************************* *****************/ NEXT_LOAD_ADDR = .; __EXTDATA_ROM = .; .extram : AT (NEXT_LOAD_ADDR) { *(.extra) . =对齐(4); } > ext_ram /************************************************* *****************/ NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.extram); /*NEXT_LOAD_ADDR = .; __DATA_ROM = .;*/ __DATA_ROM = NEXT_LOAD_ADDR; /* .PPC.EMB.sdata2 0x20100000 : AT (NEXT_LOAD_ADDR)*/ .PPC.EMB.sdata2 : AT (NEXT_LOAD_ADDR) { _SDA2_BASE_ = .; __SDATA2_START__ = .; *(.PPC.EMB.sdata2) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.PPC.EMB.sdata2); .sdata2 : AT (NEXT_LOAD_ADDR) { *(.sdata2) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.sdata2); .PPC.EMB.sbss2 : AT (NEXT_LOAD_ADDR) { *(.PPC.EMB.sbss2) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.PPC.EMB.sbss2); .sbss2 : AT (NEXT_LOAD_ADDR) { *(.sbss2) __SBSS2_END__ = .; . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.sbss2); 。数据 : { *(。数据) *(。数据。*) *(.gnu.linkonce.d*) 建设者 . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.data); .data1: { *(.data1) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.data1); 提供 (__GOT_START__ = .); 。得到 : { *(。得到) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.got); .got.plt : { *(.got.plt) . =对齐(8); } > ext_ram 提供 (__GOT_END__ = .); NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.got.plt); .got1 : { *(.got1) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.got1); 提供 (__GOT2_START__ = .); .got2 : { *(.got2) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.got2); 提供 (__CTOR_LIST__ = .); .ctors: { /*保持 (*crtbegin.o(.ctors)) 保持 (*(EXCLUDE_FILE (*crtend.o) .ctors)) 保持 (*(SORT(.ctors.*)))*/ 保持 (*(.ctors)) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.ctors); 提供 (__CTOR_END__ = .); 提供 (__DTOR_LIST__ = .); .dtors : AT (NEXT_LOAD_ADDR) { /*保持 (*crtbegin.o(.dtors)) 保持 (*(EXCLUDE_FILE (*crtend.o) .dtors)) 保持 (*(SORT(.dtors.*)))*/ 保持 (*(.dtors)) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.dtors); 提供 (__DTOR_END__ = .); 提供 (__FIXUP_START__ = .); .fixup : AT (NEXT_LOAD_ADDR) { *(。修理) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.fixup); 提供 (__FIXUP_END__ = .); 提供 (__GOT2_END__ = .); .dynamic : AT (NEXT_LOAD_ADDR) { *(。动态的) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.dynamic); .plt : AT (NEXT_LOAD_ADDR) { *(.plt) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.plt); /* 我们希望将小数据段放在一起,所以单指令偏移量 可以全部访问它们,并且在未初始化之前全部初始化数据,所以 我们可以缩短磁盘段大小。 */ __SDATA_ROM = .; .sdata: { __SDATA_START__ = .; _SDA_BASE_ = .; *(.sdata) . =对齐(8); } > ext_ram NEXT_LOAD_ADDR = NEXT_LOAD_ADDR + SIZEOF(.sdata); .PPC.EMB.sdata0 : AT (NEXT_LOAD_ADDR) { __SDATA_END__ = .; . =对齐(8); } > ext_ram __DATA_ROM_END = .; 数据 = .; _eddata = .; __eddata = .; /************************************************* *****************/ .sbss 块(4): { 提供 (__sbss_start = .); 提供 (___sbss_start = .); *(.sbss) *(.scommon) *(.dynsbss) } > ext_ram .PPC.EMB.sbss0 块(4): { *(.PPC.EMB.sbss0) 提供 (__sbss_end = .); 提供 (___sbss_end = .); 提供(__SBSS_END__ = .); } > ext_ram .bss 块(4): { 提供 (__bss_start = .); 提供 (___bss_start = .); *(.dynbss) *(.bss) *(常见的) 提供 (__bss_end = .); } > ext_ram .isrvectbl BLOCK (4) (NOLOAD): ONLY_IF_RW { . =对齐(0x800); 保持(*(.isrvectbl)) } > ext_ram /* 软件向量模式的 ISR 表 */ /************************************************* *****************/ /* 堆从低地址增长到高地址 堆栈从高地址向低地址增长 */ /* 定义堆的位置 */ /* 默认为与 RAM 中的 .bss 部分相邻的位置 */ _end = 定义(__heap_start)? __heap_start:对齐(8); 提供(结束 = _end); 提供(__end = _end); /************************************************* *****************/ .gcc_except_table : {*(.gcc_except_table)} /* 这些对于 ELF 后端是必需的,但还没有 转换为新样式的链接器。 */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } /* DWARF 调试部分。 DWARF 调试部分中的符号相对于开头 所以我们从 0 开始。 */ /* 矮人 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 扩展 */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 和 DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* 矮人 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 扩展 */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } /* */ .eh_frame 0 : { *(.eh_frame) } /************************************************* *****************/ __SRAM_CPY_START = 地址(.PPC.EMB.sdata2); __IV_ADDR = 地址(.xcptn); __SRAM_LOAD = (_end); __SRAM_LOAD_SIZE = (SIZEOF(.flash_data) / 4); __EXTRAM_CPY_START = 地址(.extram); __EXTRAM_CPY_END = ADDR(.extram)+SIZEOF(.extram); __BSS_SIZE = ((__bss_end - __bss_start) / 4); __SBSS_SIZE = ((__sbss_end - __sbss_start) / 4); TEMPSIZE = SIZEOF(.PPC.EMB.sdata2)+SIZEOF(.sdata2)+SIZEOF(.PPC.EMB.sbss2)+SIZEOF(.sbss2)+SIZEOF(.data)+SIZEOF(.data1); TEMPSIZE = TEMPSIZE + SIZEOF(.got)+SIZEOF(.got.plt)+SIZEOF(.got1)+SIZEOF(.got2)+SIZEOF(.ctors); TEMPSIZE = TEMPSIZE + SIZEOF(.dtors)+SIZEOF(.fixup)+SIZEOF(.dynamic)+SIZEOF(.plt); TEMPSIZE = TEMPSIZE + SIZEOF(.sdata)+SIZEOF(.PPC.EMB.sdata0); __ROM_COPY_SIZE = (TEMPSIZE); __DATA_VMA = 地址(.data); __DATA_LMA = LOADADDR(.data); __DATA_LMA_END = __DATA_LMA + SIZEOF(.data); __GOT_VMA = ADDR(.got); __GOT_LMA = LOADADDR(.got); __GOT_LMA_END = __GOT_LMA + SIZEOF(.got); __GOT2_VMA = 地址(.got2); __GOT2_LMA = LOADADDR(.got2); __GOT2_LMA_END = __GOT_LMA + SIZEOF(.got2); __SDATA_VMA = 地址(.sdata); __SDATA_LMA = LOADADDR(.sdata); __SDATA_LMA_END = __SDATA_LMA + SIZEOF(.sdata); }

编辑1: 当我 make all 时,我没有收到任何错误/警告。 链接器应该为 external memory 构建一切,从 0x20 000000 开始。

【问题讨论】:

    标签: c embedded gnu ld


    【解决方案1】:

    您的链接器脚本似乎试图压缩图像以存储在闪存中。 在运行时,您的图像被复制到其他地址可能是因为 MMU 对齐限制。

    链接器是否发出错误消息,或者这只是您的代码在运行时的行为不正确?

    如果您“向后”复制部分,则可以轻松绕过您提到的复制问题。

    将 .data 部分的最后一项复制到其运行时地址,然后将倒数第二项复制到其运行时地址...

    【讨论】:

    • 请丢弃链接描述文件中的任何 cmets,因为人们已经完成了许多更改,但实际上并未更新 cmets。链接器应该为从 0x20000000 开始的外部存储器构建映像。你的建议应该有效,但它似乎是一个肮脏的黑客。你知道这个不合理的 VMA/LMA 地址的原因吗?当我检查精灵/地图文件时,一切似乎都井井有条,这意味着一切都在 0x20 xxx xxx 地址。
    • 我想您构建的映像已通过某种引导加载程序传输到某种类型的嵌入式系统。大多数引导加载程序从某种类型的闪存或通过网络连接将映像作为连续的字节块撕掉。图像中的任何间隙(例如 .xptcn 和 .extram 都必须保存/传输为显式零 -> 浪费空间/带宽。因此,通过在没有所需空白的情况下一个接一个地添加部分来“压缩”图像。映像本身负责将这些部分复制到它们的最终运行时地址。
    • 因此,在这种情况下,向后复制并不是一种技巧。如果添加图像的 LMA,您可以看到它们是连续的。
    • @wpaulus,我不应该得到某种错误/警告,表明 .data 部分的 LMA 和 VMA 重叠吗?
    • 不,因为它们用于不同的情况。在映像运行期间,只有 VMA 地址很重要。唯一使用 LMA 地址的情况是在某种映像引导代码中,必须仔细设计以将部分复制考虑在内。
    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 2016-11-15
    • 2021-04-26
    • 2018-03-07
    • 1970-01-01
    • 2014-11-05
    • 2017-07-17
    • 2016-10-26
    相关资源
    最近更新 更多