Обобщение обсуждения из комментариев:
Код загрузчика в этом примере (не в вопросе, а на связанном сайте) жестко запрограммирован для загрузки ядра путем чтения 2 секторов с диска. Так что это будет работать только в том случае, если размер образа ядра меньше 1 КБ. С вашим модифицированным кодом ваше изображение оказалось больше 1 КБ (по факту 8 КБ). Таким образом, вы не загружали все это, и, в частности, вы не загружали часть изображения, содержащую ваш строковый литерал. Таким образом, когда вы обращались к ней, вы получали содержимое неинициализированной памяти, которая, по-видимому, начиналась с нулевого байта, что давало вам эквивалент пустой строки.
Вам нужно будет отслеживать размер вашего образа ядра по мере того, как вы будете писать больше кода и поддерживать синхронизацию загрузчика: посмотрите на mov dh, 2
после load_kernel
и замените 2 на соответствующее число 512 байт. сектора. Для более серьезного проекта вы хотели бы придумать более надежный механизм: например. первый сектор образа ядра может содержать заголовок, указывающий, сколько еще секторов нужно прочитать.
Большинство настроек компилятора и компоновщика помещают строковые литералы в раздел данных только для чтения (например, .rodata
), отдельно от раздела кода (.text
), и размещают каждый раздел так, чтобы он занимал второй набор из 4 КБ, чтобы можно было соответствующим образом установить разрешения на постраничную память (чтение и выполнение для .text
, чтение и отсутствие выполнения для .rodata
). Таким образом, даже если ваш код и данные могут поместиться в 1 КБ, необходимость размещения кода и данных на отдельных страницах, вероятно, объясняет размер файла 8 КБ (2 * 4 КБ). Если вы добавите данные для чтения и записи (например, глобальную переменную, которая не является const
), вы, вероятно, увидите увеличение еще на 4 КБ.
Вы уверены, что раздел вашего образа, содержащий строковые литералы, был правильно загружен в память вашим загрузчиком и по правильному адресу?
да, я могу писать символы с помощью функции print_char(), однако функция print_string() принимает строковую переменную как нулевую, и я думаю, что это вызов функции
Я не понимаю, что вы подразумеваете под «получает как ноль». Это нулевой указатель или ненулевой указатель, который указывает на нулевой байт или что? Какой тест вы делаете, чтобы прийти к такому выводу?
если я определяю строку в самой функции, она будет отображаться нормально
хорошо, я сделал проверку: if(string[i] == 0){переменная равна нулю (я думаю)}
Итак, это проверка, является ли первый байт
string
нулевым байтом. И если это так, это согласуется с моей теорией о том, что раздел строковых литералов не был загружен. Когда вы «определяете строку в самой функции», вы делаете это черезconst char *string = "Hello";
илиconst char string[] = "Hello";
? Если последнее работает, это также соответствует, потому что теперь это не строковый литерал.В частности, в коде
load_kernel
жестко запрограммировано загружать 2 сектора, то есть 1024 байта. Вы убедились, что вашkernel.bin
на самом деле 1024 байта или меньше?Когда я пробую приведенные там команды, я получаю
kernel.bin
, что составляет около 128 МБ! Вероятно, у меня другой сценарий компоновщика по умолчанию, чем тот, который использовал автор, что является частью проблемы - они должны были написать сценарий компоновщика вместо того, чтобы полагаться на-T
, чтобы попытаться взломать макет. Но, в частности,.rodata
со строковыми литералами составляет одну страницу (смещение 4 КБ), поэтому, в частности, загрузка 2 секторов не подберет его.вы объявили прототип перед основным для
void print_string(const char *string)
? Или лучше переместите эту функцию вверх. Функция должна быть объявлена перед использованием@phuclv Я тоже задавался этим вопросом, но это должно выдавать предупреждение о «недопустимом преобразовании указателя в int»?
@MartinJames да, будут предупреждения, но не это godbolt.org/z/edTvjKcxe
Да, неявное объявление
int print_string();
с неопределенными аргументами, так что это все равно должно работать. По крайней мере, я не понимаю, как это может привести к заявленному отказу.Что произойдет, если вы упростите свою функцию, пропустив на данный момент обработку смещения, обработку курсора и обработку специальных символов?
@NateEldredge Я делаю это через второй вариант:
const char string[] = "Hello!";
, мой файл kernel.bin весит 8 КБ, я думаю, это он, спасибо@phuclv да, я объявил функцию в video.h и включил библиотеку в main.c, компилятор и компоновщик не дают мне никаких предупреждений или замечаний
и я использую win10 и mingw для сборки