Я знаю, что на этот вопрос довольно сложно ответить, в основном потому, что есть так много вещей, которые могут быть не правы, и трудно что-то определить. Но я дам столько информации, сколько смогу; надеюсь, это поможет.
Я начал писать свое собственное ядро с использованием языка D и компилятора Digital Mars D, и после многих трудностей с выяснением того, как генерировать плоские двоичные файлы, которые можно перемещать, я наконец-то пришел к мысли о генерации обычного PE-файл для адреса 0xC0000000
и замены всех его заголовков байтом 0x90
(код операции NOP). Это прекрасно работало, и я мог писать что-то на экране, настраивать подкачку страниц, входить в защищенный режим и т. Д. На отлично, конечно же, с помощью 16-разрядного загрузчика на основе сборок.
Все было хорошо, то есть я решил портировать библиотеку времени выполнения D для использования в моем ядре. Мне удалось извлечь часть библиотеки и изменить ее, чтобы она скомпилировалась в мое приложение. Затем я запустил свою программу. (Примечание: я не вообще использовал библиотеку; мой код был первым кодом, выполнявшимся после загрузки - первым, что произошло, было печать "Kernel"
на экране, и никакой код времени выполнения до этого не вызывался.)
Массив D (и, следовательно, строка, поскольку строка - это просто char[]
) - это не более чем структура с указателем и элементом размера, поэтому в 32-разрядной системе он будет иметь размер 8 байт. Самое смешное, что когда я запускал свою программу, члены структуры показывали ноль , то есть и указатель, и размер были равны нулю. (Я проверил это, напечатав значение указателя на экране, а также член длины - оба были равны нулю.) Как только я удалил исходный код для среды выполнения (которая никогда не выполнялась в любом случае), они работали нормально .
Я сузил это до двух возможностей:
Стек был как-то настроен неправильно: я исключил это, потому что все работало без библиотеки времени выполнения, и я подтвердил, что никакой другой код не выполнялся до моего кода путем разборки файла.
Что-то смешное в секциях PE-файла: я проверил и выяснил, что в версии с исполняемой версией было две переменные TLS (локальные для потока). Конечно же, когда я сделал их общими (а не локальными), мой код работал! Однако , мой код все еще показывал проблему , такую же , когда я вызывал код, который я написал в другом файле - только kernel.d
, который является файлом запуска, вел себя правильно со строками ; в других файлах массивы снова были равны нулю.
Теперь, кто-нибудь догадывается, почему это может происходить?
Если понадобится дополнительная информация, я буду рад опубликовать ее.
Спасибо!