为什么这个引导程序只打印' S'

时间:2016-08-19 16:53:25

标签: c gcc x86 bootloader

我正在编写一个简单的x86引导程序。

这是我遇到问题的c程序:test4.c

__asm__(".code16\n");
__asm__("jmpl $0x0, $main\n");

void prints ( char* str )
{
    char* pStr = str;

    while( *pStr )
    {
        __asm__ __volatile (
            "int $0x10"
            :
            : "a"(0x0e00 | *pStr), "b"(7)
        );
        pStr++;
    }
}

void main ( ) 
{
    char*  str = "\n\rHello World\n\r";
    char* pStr = str;

    while( *pStr )
    {
        __asm__ __volatile (
            "int $0x10"
            :
            : "a"(0x0e00 | *pStr)
        );
        pStr++;
    }
    prints ( str );

}

当我尝试在main函数中打印字符串时,它可以工作。但是当我将字符串传递给另一个执行相同指令但仍然只打印S到屏幕的函数时。所以最终输出看起来像这样:

Hello World
S

以下是我使用的链接器文件:test.ld

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.text);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xaa55);
    }
}

以下是我用来编译c程序并链接它的命令

$ gcc -c -g -Os -m32 -march=i686 -ffreestanding -Wall -Werror test4.c -o test4.o
$ ld -melf_i386 -static -Ttest.ld -nostdlib --nmagic -o test4.elf test4.o
$ objcopy -O binary test4.elf test4.bin

我使用bochs模拟器来测试这个引导加载程序

1 个答案:

答案 0 :(得分:4)

你不能用GCC做到这一点。忽略所有可能的教程 - 他们错了。

要记住的最重要的是 GCC不是16位编译器__asm__(".code16\n")指令不会将其变为一个;它只是将汇编器混淆为从32位x86到16位重定向GCC的输出。这将导致奇怪和意外的行为,尤其是在使用指针的任何代码中。

如果要编写x86引导加载程序,则需要:

  • 使用可专门针对16位x86的C编译器("实模式")。例如,考虑OpenWatcom工具链。

  • 非常熟悉x86实模式的怪癖 - 特别是细分。

  • 在程序集中编写引导程序的某些部分,尤其是启动代码。