You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

链接脚本位置计数器与丢弃段问题:__stack_top值不符预期

问题分析与解决方案

你的问题核心在于对链接脚本中**链接地址(VMA)和加载地址(LMA)**的混淆,以及对栈起始位置的错误预期,和.eh_frame无关(该段已被/DISCARD/丢弃,不会占用任何地址空间)。

1. 为什么__stack_top不是预期的0x8E00?

你预期的0x7C00 + 0x200(512字节) + 0x1000 = 0x8E00,是假设栈的起始位置在引导扇区加载地址的末尾(0x7C00+512=0x7E00),但你的链接脚本并没有这么定义:

  • 链接脚本中,.text段的VMA(程序运行时的内存地址)从0x7C00开始,包含了entry.o(.text)、所有.text、.data、.rodata,还有.bss和COMMON段。.bss段虽然在磁盘上不占空间,但链接器会为它分配连续的VMA地址,所以.text段的VMA结束位置取决于代码+数据+bss的总大小,而不是固定的512字节。
  • .sig段的VMA是紧接着.text段的VMA结束位置的,它占用2字节的VMA空间(虽然它的LMA是磁盘上的510字节处,用于满足引导扇区签名要求)。
  • __stack_bottom被定义在.sig段之后,也就是.text段VMA结束+2字节的位置,然后加上0x1000得到__stack_top。

你在gdb中看到的0x8c93,计算可知:0x8c93 - 0x1000 = 0x7c93,说明__stack_bottom是0x7c93,这意味着.text段的VMA结束在0x7c91,加上.sig的2字节后到0x7c93——这完全符合链接脚本的逻辑:栈的起始位置是跟着程序实际占用的VMA地址走的,不是固定的引导扇区末尾。

2. 如何让__stack_top等于预期的0x8E00?

如果想强制栈从0x7E00(0x7C00+512)开始,你需要直接在链接脚本中固定__stack_bottom的地址,而不是让它跟着前面的段走:

修改链接脚本的栈定义部分:

/* 直接将栈底设置为引导扇区加载地址+512字节的位置 */
__stack_bottom = 0x7c00 + 0x200;
__stack_top = __stack_bottom + 0x1000;

同时,为了确保引导扇区的磁盘文件大小正好是512字节(符合BIOS加载要求),你需要确保.text段的LMA部分(代码+数据+rodata)加上.sig的2字节不超过512字节。如果你的代码+数据超出了512字节,BIOS加载时会截断后面的内容,导致程序运行错误。

额外注意事项

  • .bss段需要你自己手动清零,因为BIOS只会加载磁盘上的内容(即.text的LMA部分和.sig),不会初始化.bss段的内存。你可以在mystart中添加清零.bss的代码:
    mov $__bss_start, %edi
    mov $__bss_end, %ecx
    sub %edi, %ecx
    xor %eax, %eax
    rep stosb
    
  • 你的C代码中,main函数里的char s[]是局部变量,会被分配在栈上,这没问题,但要确保栈的大小足够(你设置的0x1000字节栈完全够用)。

内容的提问来源于stack exchange,提问作者InsaneCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:32:49