Ton*_*nyK 5 embedded gcc arm linker-scripts
编辑添加:我现在已将此交叉发布到GNU ARM Embedded Toolchain站点,因为我相当确定这是一个链接器错误。
另外,我注意到当第一个程序段适合 ELF 文件的第一页时(即它在其页内的起始偏移量 >= ELF 标头中的字节数)似乎会发生这种情况。在这种情况下,段错误地向下扩展到文件的开头。这可以解释为什么如果起始地址的页内偏移量从 0x80 减少到 0x40,问题就会消失。
我正在为 ARM Cortex M0 实现一个独立的操作系统,但我的链接器有一个奇怪的问题。这是我的源文件OS.c,经过精简以说明问题:
int EntryPoint (void) { return 99 ; }
Run Code Online (Sandbox Code Playgroud)
这是我的链接器脚本文件OS.ld,只需将所有代码分配给从以下位置开始的区域0x10080:
MEMORY
{
NVM (rx) : ORIGIN = 0x10080, LENGTH = 0x1000
}
SECTIONS
{
.text 0x10080 :
{
OS.o (.text)
} > NVM
}
Run Code Online (Sandbox Code Playgroud)
我编译并链接它:
arm-none-eabi-gcc.exe -march=armv6-m -mthumb -c OS.c
arm-none-eabi-gcc.exe -oOS.elf -Xlinker --script=OS.ld OS.o -nostartfiles -nodefaultlibs
Run Code Online (Sandbox Code Playgroud)
现在,当我用 列出程序段时readelf OS.elf -l,我得到:
Elf file type is EXEC (Executable file)
Entry point 0x10080
There are 1 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x00010000 0x00010000 0x0008c 0x0008c R E 0x10000
Run Code Online (Sandbox Code Playgroud)
据此,唯一的程序段开始于0x000000ELF 输出文件中的偏移量,这很疯狂:该区域包含与操作系统无关的 ELF 头信息。并且物理起始地址是0x00010000,它在我的硬件中不存在。
但奇怪的是,如果我在链接器脚本文件中更改0x10080to 的两个实例0x10040,它就可以工作!我得到:
Elf file type is EXEC (Executable file)
Entry point 0x10040
There are 1 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x010040 0x00010040 0x00010040 0x0000c 0x0000c R E 0x10000
Run Code Online (Sandbox Code Playgroud)
现在程序段位于文件中的正确位置,并且具有长度0x0000c而不是0x0008c. 不幸的是0x00010040,我的硬件中也不存在地址,因此这不是解决方案。
这是 GCC ARM 编译器中的错误吗?运行它--version给出:
arm-none-eabi-gcc.exe (GNU Tools for Arm Embedded Processors 7-2018-q2-update) 7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907]
Run Code Online (Sandbox Code Playgroud)
您所看到的可能不是您所期望的,但无论如何都是正确的,恕我直言。
ELF 是为 System V 创建的。支持虚拟内存和mmap()(将文件内容映射到内存的系统调用)的操作系统。
您正在查看 ELF 程序头(不是节头,见下文)。程序头是向(支持虚拟内存的)操作系统的 ELF 加载程序提供的信息,说明应将mmap()(完整)ELF 文件放入其准备为进程映像的虚拟内存中的位置。然后,该操作系统将在某处分配一个(或多个)页面,将其称为(虚拟)0x10000(对于该进程),映射文件并跳转到 0x10080(入口点)。
对于第二个示例,这将不起作用,因为您在ELF 文件头(ELF 头 + 程序头 + 节头)末尾之前指定了(虚拟)起始地址,因此它不能仅将文件映射到页面边界,从而使对于操作系统来说,执行此mmap()操作更加复杂(甚至不可能)。
对于您的裸机操作系统(很可能不支持虚拟内存,至少在启动时不支持),ELF 程序头的信息可能完全不相关。
您可能更应该查看部分标题。它们描述了物理记忆。
| 归档时间: |
|
| 查看次数: |
818 次 |
| 最近记录: |