Комментарии 49
Почему Virtual Address (VA) начинается с 1000, а не с нуля я не знаю, но так делают все компиляторы, которые я рассматривал.
Видимо потому, что в ImageBase (в памяти) должен располагаться заголовок. В экзотических случаях заголовок может занимать две страницы (больше 4кб).
Когда-то (во времена MS DOS), насколько помню, от нуля до 0x1000 располагались векторы прерываний. А код — с адреса 0x1000. В .exe файлах, а были еще .com, у последних такого требования не было, и размер их был хоть единицы байт, но не более 64 КБ.
А что такое Unreal Mode на x86?
Просто я так делал и это работало. Картинок, жаль не осталось, но тогда и социальных сетей не было…
Мне кажется, что речь идёт о файле, вмещающемся в один сегмент, но после запуска выделяющем себе ещё два сегмента под промежуточные результаты.
Поэтому программы компилируются в несколько проходов. Например секция .rdata идет после секции .text, при этом мы не можем узнать виртуальный адрес переменной в .rdata, ведь если секция .text разрастется больше чем на 0x1000 (SectionAlignment) байт, она займет адреса 0x2000 диапазона. И соответственно секция .rdata будет находиться уже не в адресе 0x2000, а в адресе 0x3000. И нам будет необходимо вернуться и пересчитать адреса всех переменных в секции .text которая идет перед .rdata.
Писать секции в файл не обязательно в этом порядке. Я в итоге сделал так что .data пишется первой и тогда всё расчитывается в один проход, просто RIP-относительный оффсет получится отрицательным.
Порядок секций в файле может быть любым, но насколько я помню он должен совпадать с порядком в IMAGE_SECTION_HEADER (хотя вот это может быть и не критично), а вот что точно должно соблюдаться это порядок VA.
Если секция с VA = 0x2000 шла перед 0x1000 то exe переставал запускаться.
На просторах интернета находил и совсем фантастические варианты (97 байт?!), но такое запускается при ну очень специфических условиях
В моем компиляторе всего один файл который занимается и компиляцией и линковкой.
Поэтому везде и написано компилятор, хотя внутри у него есть отдельный модуль с названием Linker.
Конечно придётся ещё и таблицу символов эмитить, но кмк это в целом будет иметь бОльшую практическую пользу, чем генератор PE/ELF из хелоувордов. Реализация формата не сложна как со стороны компилятора, так и со стороны компоновщика, можно даже в сорсы llvm не лазить.
С этим уже можно подойти и к совместимости с другими инструментами. Сделать сначала свой компилятор, результаты его деятельности скармливать компоновщику из VS или LLVM. Потом и компоновщик свой, который сможет переварить OBJ от стороннего компилятора.
Кстати, сорсы NT'шного загрузчика вполне доступны для изучения — это как минимум избавит от вопросов о правилах размещения секций PE в АП.
Ну кстати пока встроенный в windows 10 антивирус ничего не сказал.
Но помню что это было реальной проблемой когда рисовал через GDI, что на паскале, что на C++. Интересно, что достаточно было поменять 2 строки кода местами как антивирус переставал ругаться.
Иногда проблема касается и профессионалов: разработчики Go тоже жаловались.
elf вообще легко пишется
Создаем EXE