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

C函数传递常量字符串异常:my_memcpy循环未执行问题求助

核心排查方向与修复建议

让我们一步步拆解你遇到的问题——my_memcpy里的for循环完全没执行,这大概率是代码加载、链接或者函数执行流程出了问题,而非循环本身的语法错误。下面是几个核心排查方向:

1. my_memcpy函数本身的致命bug(先解决最直观的问题)

你的my_memcpy实现里有个严重逻辑错误:循环体里只做了*(char *)dst = *(char *)src;,但没有移动指针!也就是说,每次循环都在覆盖同一个目标地址的内容,哪怕循环执行了,结果也只是把src的第一个字符复制8次到dst的第一个位置。不过你说循环“完全没有执行”,那可能函数根本没被调用到,但这个bug先记下来,后续一定要修复:

static void my_memcpy(void *dst, void *src, u32 length) {
    u32 i = 0;
    char *d = (char *)dst;
    char *s = (char *)src;
    for (i = 0; i < length; i ++) {
        *d++ = *s++; // 必须移动指针才能遍历整个内存块
    }
    // ... 后面的逻辑
}

2. 链接脚本linker.ld的段布局错误

你的链接脚本存在重复定义和段顺序问题,这会导致代码和数据被放到错误的内存位置:

  • 重复定义了.data段:先是一个包含.bss、.data等的.data块,后面又单独定义了一次.data,这会让链接器的段布局混乱。
  • .bss段应该放在.data之后,冗余的PROVIDE指令也会干扰段布局。
  • 最关键的:MBR要求整个引导程序(包括代码、数据、签名)必须不超过512字节,你的脚本里.data段紧跟在.text之后,可能导致bootblock.bin超过512字节,BIOS只会加载前512字节,后面的bootmain代码被截断,根本没机会执行。

修复后的linker.ld应该严格控制在512字节内:

ENTRY(start);
SECTIONS {
    . = 0x7C00;
    .text : AT(0x7C00) {
        _text = .;
        *(.text);
        *(.rodata);
        _text_end = .;
    }
    .data : {
        _data = .;
        *(.data);
        *(.bss);
        *(.bss*);
        *(COMMON);
        _data_end = .;
    }
    /* 强制留最后2字节放MBR签名0xaa55 */
    . = 0x7DFE;
    .signature : {
        SHORT(0xaa55);
    }
    /DISCARD/ : { *(.eh_frame .note.GNU-stack) }
}

3. Makefile中OBJCOPY的参数问题

你的Makefile里用了-j .text参数,只把.text段导出成二进制,但bootmain.c的代码虽然在.text,但serial_buffer等数据在.data/.bss段,这部分数据会被丢弃,导致serial_buffer地址无效,甚至bootmain的代码因为段布局问题没被完整包含。

修改OBJCOPY命令,导出所有必要的段:

$(OBJCOPY) -S -O binary bootblock.o bootblock.bin

或者明确指定要包含的段:-j .text -j .data -j .bss

4. 验证bootblock.bin的大小与完整性

执行ls -l bootblock.bin,确保文件大小正好是512字节。如果超过512字节,说明引导程序太大,BIOS加载时会截断后面的代码,导致bootmain从未被调用。

你可以用objdump -x bootblock.o查看各个段的大小和地址,计算.text + .data + .bss的总大小是否小于510字节(留2字节给签名)。

5. 加载代码的file_load函数的地址问题

你的file_load把二进制加载到CODE_START + offset,但CODE_START的值是多少?如果CODE_START不是0x7C00,那代码被加载到错误的物理地址,CPU执行的是垃圾指令,自然不会走到bootmain和my_memcpy。

确保CODE_START定义为0x7C00,和链接脚本里的起始地址一致。

6. 验证bootmain是否被正确调用

在bootmain的开头加个临时测试逻辑,比如:

int bootmain(void) {
    // 如果执行到这里,就停住(验证是否进入bootmain)
    asm("cli; hlt");
    my_memcpy(serial_buffer, "Abcedife", 8);
    return 0;
}

重新编译加载后,如果系统停住,说明bootmain被调用了,问题出在my_memcpy的循环逻辑;如果没停,说明bootmain根本没被执行,问题出在bootasm.S到bootmain的跳转,或者代码加载错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:07:00