2016-08-19 8 views
0

Я пишу простой загрузчик x86.Почему этот загрузчик только печатает 'S'

это с программой, что им возникли проблемы с: 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); 

} 

, когда я пытаюсь напечатать строку в основной функции, она работает. Но когда я передаю строку другой функции, которая выполняет одни и те же инструкции, но все же печатает только S на экране. Таким образом, окончательный вывод выглядит примерно так:

Hello World 
S 

Вот файл линкера я использовал: test.ld

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

Вот команды я использовал для компиляции программы С и связать его

$ 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 эмулятор, чтобы проверить этот загрузчик

+0

Отдельная программа должна настраивать регистры стека и сегмента. – stark

+0

См. Комментарий duskwuffs относительно использования 16-битного кода GCC. Openwatcom - лучший выбор для _C_ компилятора, нацеленного на 16-битный код IMHO. Однако, если вы знаете, что делаете, понимаете нюансы о сгенерированном коде GCC (и его ограничения), вы можете посмотреть на что-то вроде этого [пример кода] (http://www.capp-sysware.com/misc/ ircasm/gccboot /). Это в значительной степени предназначено для печати с использованием прерываний BIOS от загрузчика. –

+1

Довольно точный дубликат [Помощь в создании 16-битных ОС] (http://stackoverflow.com/questions/2713340/help-in-building-an-16-bit-os) –

ответ

4

Вы не можете сделать это с помощью GCC. Игнорируйте все учебники, которые говорят, что вы можете - они ошибаются.

Самое главное иметь в виду, что GCC не является 16-разрядным компилятором. Директива __asm__(".code16\n") не превращает ее в одну; он просто путает ассемблер с перенастройкой GCC с 32-битного x86 на 16 бит. Это вызовет странное и неожиданное поведение, особенно в любом коде с помощью указателей.

Если вы хотите написать x86 загрузчик, то вам нужно:

  • Используйте C компилятор, который может специально предназначаться для 16-битного x86 («реальный режим»). Рассмотрим, например, инструментальную цепочку OpenWatcom.

  • Станьте очень знаком с причудами реального режима x86 - особенно сегментации.

  • Напишите несколько частей загрузчика в сборке, особенно код запуска.

+0

Я также рекомендовал бы, если вы используете OpenWatcom нацелен на 16-битный код, и вы планируете сделать это из загрузчика - [JLOC] (http://geezer.osdevbrasil.net/johnfine/jloc.htm) компоновщик - это находка. К сожалению, это программа DOS без исходного кода, но будет хорошо работать с эмуляторами, такими как DOSEMU на Linux. –

+1

Я не рекомендую использовать GCC для 16-битного кода по причинам, которые вы дали. Однако это действительно выполнимо, но только если у вас есть отличное понимание того, что происходит под капотом. У вас будут все проблемы с указателями, но они могут быть сведены к минимуму, если вся программа может быть загружена в память в первые 64k памяти, и если CS = DS = ES = SS = 0. Конечно, ни один из кодов, генерируемых директивой GCC '.code16', не будет работать ни на чем раньше, чем на процессоре 386 (8086/80186/80286 и вариантах). –