为何objcopy会从ARM裸机程序二进制文件中移除startup段?
ARM裸机项目自定义启动段转二进制丢失问题解决
你遇到的问题核心是自定义的STARTUP_SECTION段缺少ALLOC(内存分配)属性,并非默认是NOLOAD类型。
原因分析
GNU汇编的.section指令中,第二个参数的属性字符决定了段的特性:
"x"仅表示段是可执行的,但没有告诉链接器需要为该段分配内存空间。- 只有带有
"a"(ALLOC)属性的段,链接器才会将其标记为需要加载到目标内存的段。没有这个属性的段,虽然会保留在ELF文件中,但objcopy生成二进制镜像时会跳过这类无需加载的段——这就是你看到.startup段在ELF里存在但二进制里缺失的原因。
你的汇编代码里只写了.section STARTUP_SECTION, "x",遗漏了"a"属性,导致链接后的段不具备ALLOC标记。
解决方法
方法1:修改汇编代码的段属性
在section定义里加上"a"属性,同时保留"x"(可执行):
.section STARTUP_SECTION, "ax" _reset: b reset_handler @ Reset b . @ Undefined instruction b . @ SWI b . @ Prefetch Abort b . @ Data Abort b . @ reserved b . @ IRQ b . @ FIQ reset_handler: @ some code here b . @ then .text and .data section
"ax"表示该段既是可执行的,又需要分配内存空间。重新编译链接后,段会被标记为ALLOC,objcopy转二进制时就会包含这段内容。
方法2:在链接脚本中显式指定段加载属性
如果不想修改汇编代码,可以在链接脚本的.startup段定义中,通过AT()指定加载地址,并确保段被分配到内存区域:
ENTRY(_reset) SECTIONS { . = 0; .startup . : AT(0) { startup.o (STARTUP_SECTION) reset_section_end = .; } >ROM # 根据你的实际内存类型调整 .text . : {*(.text)} .data . : {*(.data)} .bss . : {*(.bss COMMON)} }
不过更推荐方法1,因为这是从根源上给段设置正确的属性,逻辑更清晰。
验证
修改后重新编译链接,用arm-none-eabi-readelf -S startup.elf查看段信息,你会看到.startup段的属性中包含ALLOC和EXECINSTR标记,此时再执行arm-none-eabi-objcopy -O binary startup.elf startup.bin,生成的二进制文件就会包含启动段的内容了。
内容的提问来源于stack exchange,提问作者ardabro
相关产品推荐
相关产品推荐

