Ответ 1
Как уже упоминалось в @Jester, мне пришлось 0 DS
с:
@@ -4,2 +4,4 @@ _start:
cli
+ xor %ax, %ax
+ mov %ax, %ds
mov $msg, %si
Обратите внимание, что mov
не может mov
перейти к DS
: мы должны пройти через ax
: 8086- почему мы не можем перемещать немедленные данные в сегмент регистрация?
Таким образом, корень проблемы был разницей между начальным состоянием QEMU и реальным оборудованием.
Теперь я добавляю следующий 16-разрядный код инициализации ко всем моим загрузчикам, чтобы гарантировать более чистое начальное состояние. Не все из них являются обязательными, как упомянуто Майклом Петчем в комментариях.
.code16
cli
/* This sets %cs to 0. TODO Is that really needed? */
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
/* The other segments are not mandatory. TODO source */
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
/*
TODO What to move into BP and SP? https://stackoverflow.com/info/10598802/which-value-should-be-used-for-sp-for-booting-process
Setting BP does not seem mandatory for BIOS.
*/
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
Я также нашел этот близкий вопрос: C Ядро - отлично работает на VM, но не на самом компьютере?
Руководство по системному программированию Intel Manual Volume 3 - 325384-056US сентябрь 2015 г. 9.10.2 "STARTUP.ASM Listing" содержит большой пример инициализации.