Функция, получающая нулевую строку

avatar
Filipe PR
9 августа 2021 в 00:45
189
1
2

У меня следующая проблема: я передаю строку функции, однако, когда она получает строку, она получает нулевое значение и ничего не делает, я пытался решить ее несколько дней и ничего, я думая, что это ошибка в функции main()

Вот мой код:

void main(){
   clear_screen();
   print_string("Hello World!"); 
}


void print_string(const char *string){
   int offset = get_cursor();
   int i = 0;
   while (string[i] != 0) {
      if(offset >= ROWS * COLS * 2) {
         offset = scroll_line(offset);
      }
      if(string[i] == '\n') {
         offset = move_offset_to_new_line(offset);
      }else{
         print_char(string[i], offset);
         offset += 2;
      }
      i++;
   }
   set_cursor(offset);
}

Что может происходить в моем коде? Примечание. Я следую примеру на этом сайте: https://dev.to/frosnerd/writing-my-own-boot-loader-3mld

Источник
Nate Eldredge
9 августа 2021 в 01:32
0

Вы уверены, что раздел вашего образа, содержащий строковые литералы, был правильно загружен в память вашим загрузчиком и по правильному адресу?

Filipe PR
9 августа 2021 в 01:40
0

да, я могу писать символы с помощью функции print_char(), однако функция print_string() принимает строковую переменную как нулевую, и я думаю, что это вызов функции

Nate Eldredge
9 августа 2021 в 01:42
0

Я не понимаю, что вы подразумеваете под «получает как ноль». Это нулевой указатель или ненулевой указатель, который указывает на нулевой байт или что? Какой тест вы делаете, чтобы прийти к такому выводу?

Filipe PR
9 августа 2021 в 01:42
0

если я определяю строку в самой функции, она будет отображаться нормально

Filipe PR
9 августа 2021 в 01:44
0

хорошо, я сделал проверку: if(string[i] == 0){переменная равна нулю (я думаю)}

Nate Eldredge
9 августа 2021 в 01:46
0

Итак, это проверка, является ли первый байт string нулевым байтом. И если это так, это согласуется с моей теорией о том, что раздел строковых литералов не был загружен. Когда вы «определяете строку в самой функции», вы делаете это через const char *string = "Hello"; или const char string[] = "Hello";? Если последнее работает, это также соответствует, потому что теперь это не строковый литерал.

Nate Eldredge
9 августа 2021 в 01:48
0

В частности, в коде load_kernel жестко запрограммировано загружать 2 сектора, то есть 1024 байта. Вы убедились, что ваш kernel.bin на самом деле 1024 байта или меньше?

Nate Eldredge
9 августа 2021 в 02:00
0

Когда я пробую приведенные там команды, я получаю kernel.bin, что составляет около 128 МБ! Вероятно, у меня другой сценарий компоновщика по умолчанию, чем тот, который использовал автор, что является частью проблемы - они должны были написать сценарий компоновщика вместо того, чтобы полагаться на -T, чтобы попытаться взломать макет. Но, в частности, .rodata со строковыми литералами составляет одну страницу (смещение 4 КБ), поэтому, в частности, загрузка 2 секторов не подберет его.

phuclv
9 августа 2021 в 03:33
3

вы объявили прототип перед основным для void print_string(const char *string)? Или лучше переместите эту функцию вверх. Функция должна быть объявлена ​​перед использованием

Martin James
9 августа 2021 в 03:59
0

@phuclv Я тоже задавался этим вопросом, но это должно выдавать предупреждение о «недопустимом преобразовании указателя в int»?

phuclv
9 августа 2021 в 04:02
0

@MartinJames да, будут предупреждения, но не это godbolt.org/z/edTvjKcxe

Nate Eldredge
9 августа 2021 в 04:13
1

Да, неявное объявление int print_string(); с неопределенными аргументами, так что это все равно должно работать. По крайней мере, я не понимаю, как это может привести к заявленному отказу.

Yunnosch
9 августа 2021 в 05:32
1

Что произойдет, если вы упростите свою функцию, пропустив на данный момент обработку смещения, обработку курсора и обработку специальных символов?

Filipe PR
9 августа 2021 в 12:13
0

@NateEldredge Я делаю это через второй вариант: const char string[] = "Hello!";, мой файл kernel.bin весит 8 КБ, я думаю, это он, спасибо

Filipe PR
9 августа 2021 в 12:18
0

@phuclv да, я объявил функцию в video.h и включил библиотеку в main.c, компилятор и компоновщик не дают мне никаких предупреждений или замечаний

Filipe PR
9 августа 2021 в 12:23
0

и я использую win10 и mingw для сборки

Ответы (1)

avatar
Nate Eldredge
10 августа 2021 в 03:04
2

Обобщение обсуждения из комментариев:

Код загрузчика в этом примере (не в вопросе, а на связанном сайте) жестко запрограммирован для загрузки ядра путем чтения 2 секторов с диска. Так что это будет работать только в том случае, если размер образа ядра меньше 1 КБ. С вашим модифицированным кодом ваше изображение оказалось больше 1 КБ (по факту 8 КБ). Таким образом, вы не загружали все это, и, в частности, вы не загружали часть изображения, содержащую ваш строковый литерал. Таким образом, когда вы обращались к ней, вы получали содержимое неинициализированной памяти, которая, по-видимому, начиналась с нулевого байта, что давало вам эквивалент пустой строки.

Вам нужно будет отслеживать размер вашего образа ядра по мере того, как вы будете писать больше кода и поддерживать синхронизацию загрузчика: посмотрите на mov dh, 2 после load_kernel и замените 2 на соответствующее число 512 байт. сектора. Для более серьезного проекта вы хотели бы придумать более надежный механизм: например. первый сектор образа ядра может содержать заголовок, указывающий, сколько еще секторов нужно прочитать.

Большинство настроек компилятора и компоновщика помещают строковые литералы в раздел данных только для чтения (например, .rodata), отдельно от раздела кода (.text), и размещают каждый раздел так, чтобы он занимал второй набор из 4 КБ, чтобы можно было соответствующим образом установить разрешения на постраничную память (чтение и выполнение для .text, чтение и отсутствие выполнения для .rodata). Таким образом, даже если ваш код и данные могут поместиться в 1 КБ, необходимость размещения кода и данных на отдельных страницах, вероятно, объясняет размер файла 8 КБ (2 * 4 КБ). Если вы добавите данные для чтения и записи (например, глобальную переменную, которая не является const), вы, вероятно, увидите увеличение еще на 4 КБ.