Page 1 of 2

KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 9:05 am
by Kenshin
Короче, новый формат исполняемых файлов, с блекджеком и пончиками.
Вот "официальная" документация по формату KX (версия 0.0):
Downloaded 289 times
В спецификации всё описано подробно и детально, а далее я опишу покороче и в общих чертах.
KolibriOS eXecutable File Format (KX) был разработан в качестве преемника формата M0x (MENUET0x). При этом преследовались две цели: компактность (заголовка и полей в нём) и расширяемость (от версии к версии). Все KX файлы состоят из двух либо трёх частей: заголовок, необязательный подзаголовок и код/данные. Заголовок должен присутствовать обязательно и выглядит таким образом:

Code: Select all

        db      "KX", maj_kx_ver shl 4 + min_kx_ver, kx_flags
Всего четыре байта. Если подзаголовок не используется (младший бит kx_flags сброшен), то после этого сразу идёт первая инструкция программы (т.е. точка входа).
Т.е. простейшая программа выглядит примерно так:

Code: Select all

        use32
        org     0

        db      "KX", 0, 0
        
        include "macros.inc"
        
        mcall   -1
Если самый старший бит kx_flags установлен, то при загрузке программы сразу после/кода данных будет выделено дополнительно 4КБ под неинициализированные данные. После загрузки такая программа получает инициализированную кучу, стэк размером 4КБ, ESP указывает на вершину, основные регистры и флаги обнулены (кроме EAX – в нём хранится указатель на PRDB, о нём будет рассказано чуть позже). Для простых программ этого может быть достаточно, но если нужны дополнительные возможности, необходимо задействовать подзаголовок.
При использования подзаголовка, устанавливаются флаги в kx_flags (самый младший бит устанавливается в 1, биты 1-2 в 00/01/10 - для 8-/16-/32-битных чанков). Подзаголовок является линейным массивом из чанков (chunks) или фреймов и располагается сразу после заголовка. Каждый чанк состоит из заголовка (тип чанка + размер данных) и непосредственно данных. Завершает заголовок специальный чанк -1. Для версии 0.0 с помощью чанков можно определить точку входа, стартовый размер памяти процесса, размер стека, атрибуты исполняемого файла, краткое описание программы и множество чанков с таблицей импорта (один на одну библиотеку).
Файл с чанками загружаются похожим образом, но с небольшими отличиями. Если определена точка входа, EIP устанавливается на неё. Если был определён размер стэка, то выделяется не 4КБ, а указанное кол-во. Если был определён стартовый размер памяти, то выделяется память не по размеру образа программы, а указанное кол-во.
Все KX-процессы получают при запуске в EAX указатель на PRDB (Pre-Runtime Data Block). В нём загрузчик размещает следующие данные:
  • PID процесса
  • PID родителя (загрузчика)
  • указатель на строку с именем KX-файла
  • указатель на строку с переданными параметрами
Для тестирования формата был специально написан загрузчик runkx [rʌŋks].
runkx.7z (7.96 KiB)
Downloaded 223 times
В архиве также лежит тестовый KX-вариант программы calc. Пока что runkx не поддерживает все возможности формата (например, загрузку библиотек и обработку атрибутов), но большей части "стандарта" он уже соответствует. Также, пока что не реализована поддержка упаковки. Формат KX на уровне спецификации поддерживает сжатие файлов с помощью kpack (или других утилит). При этом подзаголовок и код/данные сжимаются отдельно. Заголовок никогда не сжимается.

Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 9:17 am
by Kenshin
Пример простой программы, использующей неинициализированные переменные:

Code: Select all

        use32
        org     0
        
        db      "KX", 0, 0x80
        
        call    proc0
        call    proc1
        ...
        mov     [x], 5
        mov     eax, [x]
        mov     [y], eax
        ...
        xor     eax, eax
        dec     eax
        int     0x40
        
x       dd      ?
y       dd      ?


Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 9:21 am
by Kenshin
Структура чанка с 8-битным заголовком:

Code: Select all

        db      chunk_type
        db      chunk_data_size
        db      chunk_data_size dup ? ;chunk_data
с 16-битным заголовком:

Code: Select all

        dw      chunk_type
        dw      chunk_data_size
        db      chunk_data_size dup ? ;chunk_data
с 32-битным заголовком:

Code: Select all

        dd      chunk_type
        dd      chunk_data_size
        db      chunk_data_size dup ? ;chunk_data

Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 12:41 pm
by Kenshin
Забыл написать про то, что runkx - это консольная программа, поэтому её нужно запускать в shell-е так:
runkx kxapp kxparams
или
runkx "kx app" "kx params"
Например, для того, чтобы запустить calc.test в шелле введите:
runkx calc.test

Для работы программы требуется наличие /tmp0/1 раздела и свободного места на нём.

Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 1:42 pm
by dunkaist
Hi Kenshin,

I appreciate your work and value your experience. There are, however, two things I don't get:
  1. What is the problem you are solving with another custom format?
  2. What is your position on PE-related activities in this thread? I particularly mean arguments for PE and against custom formats like the current one.

Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 3:19 pm
by Kenshin
dunkaist wrote:What is the problem you are solving with another custom format?
  1. Заголовок короче, чем M0x или PE/ELF.
  2. Меньше кода, загрузчик подготавливает всё для работы программы (стэк, память, загружает библиотеки (пока не реализовано)), выделяет необходимое кол-во памяти под строку с именем файла и строку с параметрами (т.е. не важно сколько они занимают, выделяется ровно столько места, сколько необходимо).
  3. Так как под стэк выделяется отдельный блок памяти, при переполнении произойдёт исключение General Fault, в существующих же программах при переполнении будут затираться лежащие перед стэком данные.
  4. Чтобы узнать такие важные параметры, например, как PID, теперь не нужно выделять килобайтный буфер и ждать пока его заполнит функция 9.
  5. Даже если программа в формате KX запакована, любая программа может быстро понять (т.е. не распаковывая весь файл), что это именно KX-файл, т.к. заголовок не упаковывается. Чтобы прочитать описание/иконки (будут в будущих версиях)/таблицы импорта, опять же не нужно распаковывать весь файл, достаточно разжать только данные подзаголовка.
  6. Различные фичи, которых нет в формате M0x, например краткое описание программы или аттрибуты файла (тип файла, тип используемого интерфейса (GUI/TUI и т.д.), минимальная SVN-ревизия ядра для запуска), в будущих версиях будут новые и (надеюсь) полезные фичи.
  7. Название формата, которое отражает то, что программа для KolibriOS, а не MenuetOS.

Re: KX - новый формат исполнимых файлов

Posted: Mon Feb 22, 2021 3:20 pm
by Kenshin
Против PE/ELF я ничего не имею, но идея заключалась в том, чтобы сделать формат в духе Колибри.

Re: KX - новый формат исполнимых файлов

Posted: Wed Feb 24, 2021 2:15 am
by Kenshin
runkx теперь поддерживает чанк "General Executable File Attributes", который позволяет указать вид исполняемого файла, тип используемого интерфейса (GUI/TUI или неопределённый UI для служб, демонов и т.д.), флаги исполняемого файла, а также номер минимальной ревизии ядра, которая поддерживает данный KX-файл (например, если ваша программа использует фьютексы, вам нужно указать здесь ревизию 6926, т.к. их поддержка в ядре появилась в этой ревизии, и в таком случае runkx запустит такой файл только на ядре рев. 6926+).
runkx_0.0.1b.7z (8.1 KiB)
Downloaded 206 times

Re: KX - новый формат исполнимых файлов

Posted: Wed Feb 24, 2021 2:38 am
by Kenshin
Пример программы в формате KX с использованием подзаголовка:

Code: Select all

        use32
        org     0x0

        db      "KX", 0, 0x81           ;the KX header

        db      0, 4                    ;default entry point chunk
        dd      entry_point

        db      0x20, 12                ;general executable file attributes chunk
        dw      0                       ;a regular 32-bit KolibriOS application/program
        dw      1                       ;uses GUI
        dd      0                       ;executable file flags
        dd      0                       ;any version of kernel
        
        db      0xA0, 23                ;short description chunk
        db      "myapp - my application", 0

        db      -1
        
entry_point:
        call    proc1
        call    proc2
        
        xor     eax, eax
        dec     eax
        int     0x40
        
proc1:
        ...
        ret
        
proc2:
        ...
        ret
Флаги KX, установленные в 0x81, обозначают, что данная программа использует подзаголовок и что во время загрузки будут выделены 4 КБ памяти под неинициализированные данные. Если нужно больше 4 КБ, то можно использовать чанк "Initial Process Memory Size", указав в нём начальный размер общей памяти процесса. Если программа не использует неинициализированные данные, нужно сбросить старший бит флагов (т.е. должно быть 0x01).

Re: KX - новый формат исполнимых файлов

Posted: Wed Feb 24, 2021 10:25 am
by rgimad
думаю, когда формат уже устаканится, можно попробовать внедрить поддержку данного формата в ядро.

Re: KX - новый формат исполнимых файлов

Posted: Thu Feb 25, 2021 9:33 am
by bad_Dr3dd0x
На каких языках программирования можно писать программы с использованием формата kx?

Re: KX - новый формат исполнимых файлов

Posted: Thu Feb 25, 2021 11:36 am
by maxcodehack
На любом ведь
Главное чтобы компилер смог в этот формат

Re: KX - новый формат исполнимых файлов

Posted: Fri Feb 26, 2021 1:50 pm
by GerdtR
maxcodehack wrote:На любом ведь
Главное чтобы компилер смог в этот формат
1. Вот в том и проблема. Ассемблеры. Вроде всё. Потому и первоначальный заголовок Menuet не очень. С-- научили, местные С компилеры тоже. Из pascal и C (msvc или gcc) делали ухищрения в линкерах. Для паскаля вроде прога специальная была из виндового PE делать.
2. Динамические библиотеки, линковка, как дела с этим? Этот формат для библиотек годится?
3. Ресурсы предполагаются? Или хотя бы можно ли будет хранить иконку приложения в стандартном для всей Кос месте?

Re: KX - новый формат исполнимых файлов

Posted: Fri Feb 26, 2021 10:32 pm
by Kenshin
GerdtR wrote:
maxcodehack wrote:На любом ведь
Главное чтобы компилер смог в этот формат
1. Вот в том и проблема. Ассемблеры. Вроде всё. Потому и первоначальный заголовок Menuet не очень. С-- научили, местные С компилеры тоже. Из pascal и C (msvc или gcc) делали ухищрения в линкерах. Для паскаля вроде прога специальная была из виндового PE делать.
2. Динамические библиотеки, линковка, как дела с этим? Этот формат для библиотек годится?
3. Ресурсы предполагаются? Или хотя бы можно ли будет хранить иконку приложения в стандартном для всей Кос месте?
1. Привязки к какому-то определённому языку нет, хотя да, формат лучше всего подходит для fasm'а, который может создавать практически любые файлы с самой разной структурой.
2. а) Текущая версия формата поддерживает таблицы импорта для неограниченного кол-ва библиотек, а runkx скоро научится их автоматически подключать (при этом разработчику не обязательно знать, где хранятся системные библиотеки, он может указать либо имя библиотеки полное,т.е. с путём, либо базовое - например, "libini.obg"). Сейчас для каждой библиотеки своя отдельная таблица импорта, а в версии 0.1 появится общая или универсальная таблица, описывающая импорт сразу нескольких библиотек.
б) Изначально KX разработан именно для обычных программ и приложений, т.к. есть MS COFF, но расширяемость формата позволяет в будущем использовать его для библиотек/драйверов/чего-либо ещё, если такая надобность возникнет, разумеется.
3. Да, поддержка ресурсов была запланирована с самого начала. В версии 0.1 появятся как минимум иконки, а насчёт других ништяков надо думать, ибо стандартов ресурсов (например, форм) в Kolibri практически нет. Также появятся возможность расширенного описания программы (версия, автор, дата сборки, описание и т.д.). Возможно ещё что-то будет, хотя лишних вещей в формате тоже не хочется.

Re: KX - новый формат исполнимых файлов

Posted: Tue Mar 02, 2021 4:51 pm
by ProMiNick
Kenshin, а разве код лоадера не самая информативная часть после непосредственно описания спецификации?
правильно ли я понимаю, что какой то формат тестируется вначале лоадером, и лишь потом помещается в ядро. управление памятью в пространстве адресов процесса вещь интересная. Она может быть реализована в юзермод лоадером?
А еще как загрузка библиотек стыкуется с загрузкой их системой.
Имею в виду что система загружает библиотеку в память однажды, НО...
НО если код библиотеки не адресонезависимый то в процесс загружается свой экземпляр библиотеки...
это то делает система, понятно.
Но данные и код в библиотеке адресуются процессами по разному: данные в реальной памяти полностью разделяемы по разным адресам виртуальной памяти каждого процесса, а код наоборот: для каждого виртуального адреса создается свой экземпляр в реальной памяти релоцированный на этот адрес, в пределах одного виртуального адреса разных процессов в реальной памяти создается только 1 его экземпляр.
Т.е. список подгруженных библиотек можно также на уровне лоадера хранить, а не на уровне ядра? И так вот с памятью тоже лоадер может играться?