提供意外加载地址的 GNU 链接器映射文件 [英] GNU Linker Map File Giving Unexpected Load Addresses

查看:27
本文介绍了提供意外加载地址的 GNU 链接器映射文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个嵌入式程序,其中有一个自定义链接器脚本.该程序可以运行,但我注意到链接器在内存中放置几个​​部分的方式可能存在问题.

以下是链接描述文件的相关部分:

MEMORY {ROM (rx) : ORIGIN = 0x00100000, LENGTH = 16kRAM (rwx) : ORIGIN = 0x00200000, LENGTH = 4k}部分{/* 其他部分放在这里.*/.数据 : {...} >RAM AT>ROM.bss:{...>内存.堆 : {...>内存...}

这是 MAP 文件的相关部分:

.data 0x00200040 0x0 加载地址 0x001003d40x001003d4 __data_load = LOADADDR (.data)0x00200040 __data_start = .*(.数据)*(.数据*)0x00200040.= 对齐 (0x4)0x00200040 _edata = ..igot.plt 0x00200040 0x0 加载地址 0x001003d4.igot.plt 0x00000000 0x0 ./debug/sam7s_startup.o.bss 0x00200040 0x0 加载地址 0x001003d40x00200040 __bss_start__ = .*(.bss)*(.bss*)*(常见的)0x00200040.= 对齐 (0x4)0x00200040 _ebss = .0x00200040 __bss_end__ = .0x00200040 提供(结束,_ebss)0x00200040 提供(_end,_ebss)0x00200040 提供(__end__,_ebss).stack 0x00200040 0x200 加载地址 0x001003d40x00200040 __stack_start__ = .

<小时>

因此,从映射文件来看,我认为 .bss 和 .stack 部分正在获取 ROM 中的加载地址.我认为这是因为这两行:

.bss 0x00200040 0x0 加载地址 0x001003d4
.stack 0x00200040 0x200 加载地址 0x001003d4

这不好,因为它们没有必要占用 ROM 中的空间..bss 部分虽然现在是空的,但将包含未初始化的全局变量,这些变量将在代码中设置为零.堆栈也只是将在代码中初始化的 RAM 的一部分.因此,这两个部分中的任何一个都不需要占用 ROM 中的空间.

所以我的问题是,阻止 .bss 和 .stack 加载到 ROM 的正确方法是什么?我是否必须将 .bss 和 .stack 部分的末尾从 >>RAM 更改为 >RAM AT>RAM?这似乎有点多余.

在测试了一些东西后,我发现了以下几点:

(1) 使用 (NOLOAD) 属性(例如将 .stack : 替换为 .stack (NOLOAD) :)仍然会产生结果在显示 .stack 和 .bss 部分的 ROM 加载地址的映射文件中.

(2) 如上所述,指定 RAM AT>RAM 确实会阻止映射输出显示 .stack 和 .bss 部分的 ROM 加载地址.

(3) 当映射文件显示 .bss 和 .stack 部分的加载地址时,它们似乎并没有实际占用 ROM 中的空间..stack 部分虽然有 0x200 字节长,但似乎实际上并没有占用 ROM 中的空间,即使我为它指定了填充值并在链接描述文件中在它后面放置了一个部分.链接描述文件中紧随其后的部分不会随着堆栈大小的不同而移动.

所以也许映射文件输出并不意味着我认为的意思,并且 .stack 和 .bss 部分实际上根本没有在 ROM 中被赋予加载地址.在尝试了一些事情之后,它肯定会以这种方式出现.知道为什么映射输出使它看起来好像这些部分被赋予了 ROM 加载地址仍然会很有趣,特别是当使用 (NOLOAD) 时.这可能只是 LD 如何生成其地图输出文件的错误吗?

另见:了解 GNU 链接脚本的位置计数器

您正在寻找 NOLOAD.请参阅 Gnu LD 输出节类型.我现在阅读了您的整篇文章,我看到您对 NOLOAD 进行了假设.NOLOAD 定义了所有的地址.如果您在C"代码中使用它们,它们将从该地址加载.您必须提供一些启动代码,通常是在清除BSS 区域的汇编程序中.通常,您不希望 stack 被初始化.

NOLOAD 部分就像一个编译/链接时间malloc().您可以使用内存,只是不要指望那里有任何东西.对于 BSS,您在链接描述文件中定义 __bss_start____bss_end__ 并编写一个简短的初始化例程以使用这些变量/地址清除此内存.

注意:所有内容都显示在地图文件中.它不会出现在生成的二进制文件中,也不会在 ELF 中包含数据.只是部分元信息将保存在 ELF 中.

编辑:地图文件中的加载地址就像加载的位置计数器.加载地址是 ld 被设置用来放置东西的地方.如果它们的大小为零,ld 并没有真正把东西放在那里.地图输出在语言上没有歧义;我可以看到它是多么令人困惑,但是 ld 在创建输出二进制文件时做的事情是正确的.BSS 通常在目标文件中被 gcc 标记为 NOLOAD,因此在示例中只有 stack 部分需要 NOLOAD>.对于像堆栈这样的东西,一个部分并不是真正需要的,只需要一组符号声明就可以了.

I'm working on an embedded program where I have a custom linker script. The program works, but I have noticed that there is possibly something amiss with how the linker is placing a couple of sections in memory.

Here are the relevant parts of the linker script:

MEMORY {
    ROM (rx)    : ORIGIN = 0x00100000, LENGTH = 16k
    RAM (rwx)   : ORIGIN = 0x00200000, LENGTH = 4k
}

SECTIONS {
    /* Other sections go here. */
    .data : {
...
    } >RAM AT>ROM

    .bss : {
...
    } >RAM

    .stack : {
...
    } >RAM
...
}

And here is the relevant part of the MAP file:

.data           0x00200040        0x0 load address 0x001003d4
                0x001003d4                __data_load = LOADADDR (.data)
                0x00200040                __data_start = .
 *(.data)
 *(.data*)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _edata = .

.igot.plt       0x00200040        0x0 load address 0x001003d4
 .igot.plt      0x00000000        0x0 ./debug/sam7s_startup.o

.bss            0x00200040        0x0 load address 0x001003d4
                0x00200040                __bss_start__ = .
 *(.bss)
 *(.bss*)
 *(COMMON)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _ebss = .
                0x00200040                __bss_end__ = .
                0x00200040                PROVIDE (end, _ebss)
                0x00200040                PROVIDE (_end, _ebss)
                0x00200040                PROVIDE (__end__, _ebss)

.stack          0x00200040      0x200 load address 0x001003d4
                0x00200040                __stack_start__ = .


So from the map file it looks to me like the .bss and .stack sections are getting load addresses in ROM. I think this because of these two lines:

.bss 0x00200040 0x0 load address 0x001003d4
.stack 0x00200040 0x200 load address 0x001003d4

This isn't good, because there's no point in them taking up space in ROM. The .bss section, although empty right now, will contain uninitialised global variables that will be set to zero in code. The stack is also just a part of RAM that will be initialised in code. So there's no need for either of these sections to be taking up space in ROM.

So my question is, what is the correct way to stop .bss and .stack from being loaded into ROM? Do I have to change the end of the .bss and .stack sections from >RAM to >RAM AT>RAM? This seems a bit redundant.

After testing out some things I have found the following:

(1) Using the (NOLOAD) attribute (e.g. by replacing .stack : with .stack (NOLOAD) :) still results in the map file showing a ROM load address for the .stack and .bss sections.

(2) Specifying RAM AT>RAM, as mentioned above, does indeed stop the map output from showing ROM load addresses for the .stack and .bss sections.

(3) When the map file shows load addresses for the .bss and .stack sections, it appears that they do not actually take up space in ROM. The .stack section, although 0x200 bytes long, does not seem to actually take up that space in ROM, even if I specify fill values for it and place a section after it in the linker script. The section that follows it in the linker script does not get moved around with different stack sizes.

So perhaps the map file output doesn't mean what I think it means, and the .stack and .bss sections aren't actually being given load addresses in ROM at all. After trying out a few things it would certainly appear this way. It would still be interesting to know why the map output makes it appear as though the sections are given ROM load addresses though, especially when (NOLOAD) is used. Could this just be a bug in how LD generates its map output files?

See Also: Understanding the Location Counter of GNU Linker Scripts

解决方案

You are looking for NOLOAD. See Gnu LD output section type. I read your whole post now and I see you postulated about NOLOAD. With NOLOAD, all of the addresses are defined. If you use them within your 'C' code, they will load from that address. You must provide some start-up code, usually in assembler that clears the BSS area. Usually, you don't expect your stack to be initialized.

A NOLOAD section is like a compile/link time malloc(). You get the memory to use, just don't expect anything there. For BSS you define __bss_start__ and __bss_end__ in your linker script and write a short initialization routine to clear this memory using those variables/addresses.

Note: everything shows up in the map file. It won't show up in a generated binary or have data in an ELF. Just the section meta information will be held in the ELF.

Edit: The load address in the map file is like a location counter for loading. The load address is where ld is set to put stuff. ld is not really putting things there if they take zero size. The map output is not linguistically un-ambiguious; I can see how it is confusing, but ld does things correctly in creating the output binary. BSS is normally marked NOLOAD by gcc in the object files, so in the example only the stack section would need NOLOAD. For a something like stack, a section is not really needed and just a set of symbols declarations would work.

这篇关于提供意外加载地址的 GNU 链接器映射文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆