Вступление

Небольшое предупреждение! Субъективно, эта статья содержанием немного не удовлетворяет смыслу переданному в заголовке. Я буду говорить не просто о том "Как запускаются команды?", а покажу часть внутреннего мира операционных систем и покажу принципиальную разницу в их работе.

Это моя первая статья, вырванная из моего дневника, который я веду пока что закрыто, особо не выкладывая заметки в публичный доступ.

Взгляд на CP/M

Начну очень издалека, поскольку
считаю важным немного заранее обозначить моменты, которые будут нужны.

Во времена 1970-ых годов, когда для процессоров Intel 8080 появилась на свет операционная система CP/M (полн. "Computer Program/Monitor").

CP/M 2.2b снимок экрана
CP/M 2.2b снимок экрана

Процессор i8080 (полн. "Intel 8080") был 8-разрядным,
соответственно объемы обрабатываемой памяти были не такими уж и большими. Все написанные под эту ОС программы помещались в один файл команды и весили не больше чем 64Кб.

Раз глава про управление памятью, сразу вижу необходимым обозначить структуру оперативной памяти после загрузки CP/M.

+----------------------------+ <-- 0xFFFF
|           BIOS             |        
| Аппаратные драйвера BDOS   |
+----------------------------+ <-- 0xF200
|           BDOS             |
| CP/M двоичный интерфейс    |
+----------------------------+ <-- 0xE400
|   Интерпретатор комманд    |
+----------------------------+ <-- 0xDC00
|           TPA              | 
|Область запущенной программы|
+----------------------------+ <-- 0x0100
|        LowMem Storage      |
| То, что нас интересует     |
+----------------------------+ <-- 0x0000

Объясняю по-порядку все, что может вогнать в тупик:

BDOS (полн. "Basic Disk Operating System") - это лишь часть CP/M, а не второе название системы.

Компонент BDOS действительно для первого раза лучше принять за двоичный интерфейс, так как команды CLOSE, READ, SELECT, и др, это "именно в эту дверь".

BIOS (полн. " Basic Input/Output System") это буквально то, о чём могут подумать практически все, кто это читает. Но сразу обозначусь, в понимании CP/M это её часть, а не отдельное "нечто" и POST.

Выглядит немного необычно, не так ли?
Интересно в организации ОЗУ самое первое (или последнее) пространство -- "Low Memory Storage".
Низкоуровневая память или "Low Memory Storage"
бьется на разделы тоже.

На самом деле, эту часть лучше пропустить, поскольку много кого это загонит в тупик.
Я оставлю информацию, которую я нашел в архивах, но лучше пропустить это мимо глаз.

+----------------------------+ <-- 0xFF
|       Файловый буфер       | <-- 0x80 длинна
|                            |     0x81-0xFF
|                            | Список ASCII строк
+----------------------------+
| FCB (File Control Block)   |
+----------------------------+
| ???                        |
+----------------------------+
| BIOS рабочее пространство  |
+----------------------------+
| Вектор перезагрузки #7     | <-- Использовался 
| Вектор перезагрузки #6     |     отладчиком
| .                          |
| .                          |
| Вектор перезагрузки #1     |     
+--------+------+----+-------+     
|   F200 | Disk | IO | E400  | 
+--------+------+----+-------+ <-- 0x00

Взгляд CP/M на Программы

И так, программа для CP/M это файл с расширением ".COM".

Файл ".COM" (сокр. "Command") - это монолит кода. Внутри он никак не разграничен и не имеет опознавательных знаков или подписей. В CP/M может занимать адреса до верней границы TPA (полн. "Transistent Program Area").

Напишем простой пример команды, чтобы показать структуру:

.z80               ; <-- Требуется Z80;

WRITE       equ 9h ; <-- CP/M функционал;
_BDOS       equ 5h ; <-- "Системное прерывание";

org 100h           ; <-- Отступ в ОЗУ на 255 байт;
    ld C, WRITE
    ld DE, hello
    call _BDOS     ; syscall;
    rst 0h         ; Выход.

hello:
    db "Hello World!$"
    end

На всякий случай, команда ld (полн. "LOAD") выполняется как mov из IA-32, а не как lea или push. Команда rst (полн. "RESET") переходит по адресу и запоминает предыдущее значение в стэке.

Стрелочками в комментариях я обозначил, что здесь определенно "делает погоду".
Для CP/M в структуре программы есть три
немало важные детали.

  1. требование к архитектуре;

  2. двоичный интерфейс (англ. "Application Binary Interface") системы;

  3. смещение программы (ORG 100h) и установка входной точки.

     Начало TPA -->|
                   |
<-- Low Memstr  -->|
+------------------+-----------------+
| ... | ... | ...  | Код программы   |
+------------------+-----------------+
|<--  255 байт  -->|                 |

Сама программа должна будет лежать в области TPA, как из таблицы видно, а выделенная область оказывается лежит в Low Memry Storage.
Эта таблица называется ZPCB (полн. "Zero Page Control Block") или PPA (полн. "Program Prefix Area") для поздних релизов этой системы.

Представьте себе почтовый ящик в подъезде по таковому адресу (адрес 0x0000-0x00FF это Low Memory Storage)... Когда приходит жилец (загружается комманда), почтальон (Операционная Система CP/M) кладет в этот ящик конверт с важной информацией именно для этого жильца. Конверт лежит в ящике. Жилец приходит "домой" (загружается по 0x0100 смещению) и первым делом заглядывает в свой ящик за конвертом (Содержит области памяти ещё и ZPCB).

Загрузка и регистрация .COMманды в CP/M

Когда CP/M загружает .COM файл
ОС инициализирует PPA/ZPCB в Low Storage. Она заполняет поля, относящиеся к запуску программы. Это могут быть текущий диск, FCB1, FCB2, хвост командной строки, системные векторы BDOS и BIOS для этого запуска.

ОС загружает бинарный образ .COM файла начиная с адреса 0x0100. Именно благодаря ORG 100h комманде процессору.
Код программы ожидает, что по 0x0000-0x00FF уже лежит корректно заполненная PPA.

ОС устанавливает регистры процессора: PC (полн. "Program Counter") становится по адресу точки входа, SP (полн. "Stack Pointer") - обычно глядит в конец доступной программе памяти (или в другое место, указанное в BDOS).

Zero Page Control Block или Program Prefix Area (CP/M)

Теперь более детально опишу структуру ZPCB/PPA. В документации к CP/M её действительно называют "нулевой страницей", поэтому непобоюсь написать так же.

Данную структуру в более полном виде (описания и типы данных) можно найти в архивах или на сайте с документацией.

Название поля

Размерность

Описание

bCodeGroupLength

[u8; 3]

bCodeGroupAddress

size

Адрес сегмента кодовой группы

b8080Flag

u8

Установлен, если программа в одном сегменте

bDataGroupLength

size

bReserved

u8

hExtraGroup

hGroupX1

[u8; 5]

Дескриптор группы X1

hGroupX2

[u8; 5]

Дескриптор группы X2

hGroupX3

[u8; 5]

Дескриптор группы X3

hGroupX4

[u8; 5]

Дескриптор группы X4

bReserved

[u8; 11]

bTargetFloppy

size

Диск с которого запущена программа

bFcbPasswordAddress

u8

Адрес ключевого слова для FCB #1

bFcbPasswordLength

u8

Длинна ключевого слова

dwReserved

u32

bDefaultFcb

[u8; 15]

FileControl Block #1

bFcb

[u8; 14]

FileControl Block перезаписывается, если открыт FCB #1

bArgc

u8

Количество аргументов

bArgv

[u8; 127]

Аргументы командного интерпретатора

Теперь укажу условные обозначениям:

  • Префикс b... - это BYTE или машинное слово, размером в 8 бит.

  • Префикс h... - это дескриптор (указатель) инкапсулирущий настоящий адрес данных.

  • Нотация [type; n] взята из Rust, так как нахожу это правило универсальными и более понятными глазу, чем типы данных Windows. Это массив type-ячеек в n-ом колличестве.

  • Префикс dw... - это DWORD, а не define WORD! Другими словами - машинное слово размером в 32-бит (на момент IA-32e).

  • Тип данных size тоже взят из Rust. Путь Этот тип будет для всех, как максимально возможное машинное слово для процессоров тех времен и самой ОС. (имеется ввиду Intel 8080 и Intel 8086). Все зависит только от того "Где работает ОС и какая ОС".

Как видно, тот самый "конверт" с письмом на самом деле содержит вот такие поля данных.

Очень важно запомнить, что таблица PPA в CP/M
только одна. Она располагается в определенном месте,
имеет очень большой смысл в жизненном цикле программы.

Только в CP/M-86, ZPCB (или PPA) начинает поведением быть похожа на PSP таблицу из xx-DOS.

Взгляд на xx-DOS

Сейчас речь пойдет в основном про PC-DOS и MS-DOS 2.0,
так как тема разговора и подопытные совпадают.

MS-DOS 2.0 снимок с WebArchive
MS-DOS 2.0 снимок с WebArchive

В предыдущей главе было описано более-менее подробно, как же понимает CP/M файлы комманд. Раз уж выделена отдельная глава для DOS, логично предположить, что поведение COM
файлов в DOS и CP/M разное.

Внимание, здесь не будет описан механизм чтения OVERLAY
частей программ, потому что рассматриваются немного другие времена
и лишние объяснения про страницы памяти будет избыточно.

К сожалению опять собираются грозовые тучи теории и истории, и придется их переждать, ведь без них всё высохнет и потеряет смысл.

Очень важная отличительная черта от предыдущего "подопытного" в организации процессов. Положим, MS-DOS пусть и является однозадачной, по определению, но каким-то образом же может удерживать драйверы и DOS-extender'ы? Ведь да?

В оперативной памяти DOS держится приблизительно таким образом:

Схема организации памяти в PC/MS-DOS (взято с WebArchive
Схема организации памяти в PC/MS-DOS (взято с WebArchive

Здесь логика местами похожа на CP/M, но в глаза бросается строгое разграничение программной памяти. Отныне все нулевые страницы ~управляемой~ памяти пренадлежат области "Program Memory".

Писать про жизненно необходимые MSDOS.SYS, CONFIG.SYS, COMMAND.COM не буду. Они как раз видны на схеме вооруженным глазом.

...и Взгляд xx-DOS на программы

Для 16-разрядных DOS при выполнении файла код,
данные и стек находятся в одном и том же 16-битном сегменте.
Поэтому размер файла не может превышать 65280 байт (что на 256 байт меньше размера сегмента — или 216 байт).

Простейшая программа для DOS на Flat Assembly (сокр. "FASM")
диалекте выглядит приблизительно так:

use16

DosWrite equ 9h     ;<-- Функционал DOS/2.0

org 100h            ;<-- Точка входа 0x100
    mov dx, hello
    mov ah, DosWrite;DOS call.
    int 21h         ;syscall. (вызов DOS функции)
 
    mov ax, 4C00h   ;AH = 4Ch, AL = 00h.
    int 21h         ;syscall (вызов DOS функции)

hello db 'Hello, world!$'

Стрелочками я обозначил практически те же самые места, такие как смещение и обозначение точки входа (не смещение точки входа), и ABI системы. С виду структурно это похоже на предыдущий образец. Разница только в архитектуре и в системном BI.

Впринципе, отличить .COMы можно только при детальном анализе сырого содержимого, так как дисковых операционных систем успело
появиться достаточно, и скорее всего системный интерфейс у всех отличается. Можно ловить их по опкодам прерываний, как делал это я, можно придумать более умную стратегию.

Загрузка регистрация .COMманд в MS-DOS 2

И так, идея комманды не меняется. .COM это все еще PIE-монолит (исполняемый файл независящий от точки входа).

При загрузке файла .COM в свободной области ОЗУ, операционная система
создает несколько структур.
Структура "перед" кодом программы - это PSP (полн. "Program Segment Prefix"), что отвечает за состояния
выполняемого файла и предоставляет список аргументов командной строки.

A:\> COMMAND.COM /A /B /C
argv[     0     ][1][2][3]

В области ОЗУ будет приблизительно такая схема ячеек:

+-----+-----+----------+----------------------------------+-----+
| ... | ... | PSP      | [Программа] [STACK]              | ... |
+-----+-----+----------+----------------------------------+-----+
            | 256 байт |         Размер Программы         |
            |                                             |
            |                                             |
 Начало  -->|                  Конец области программы -->|

Как видно из таблицы, именно поэтому образец программы начинался с org 100h.

Сама программа в ОЗУ разбивается по области кода, данных и стэка.
Ещё раз: здесь не рассматривается OVERLAY части, потому что это здесь избыточно.
Но в следующий раз, возможно про .EXE файлы и MS-DOS 2.0 я это обязательно возьмусь показательно разбирать.

В документации DOS я не встретил упоминания "нулевой страницы", поэтому назову структуру "как есть".

Program Segment Prefix (PSP)

Теперь спускаемся ещё дальше в специфику DOS и CP/M семейств.
С первых интернет ресурсов буквально представляется полная информация о PSP секции. Представлена ниже:

Название

Размер

Описание

wExitCode

u16

INT 0x20 код выхода программы

wSegmentAddress

u16

Сегмент расположенный после выделенной памяти

bReserved

u8

bCallFar

[u8; 5]

Содержит CALL для вызодва функции DOS

hTerminate

u32

Адрес TERMINATE обработчика

hBreak

u32

Адрес BREAK обработчика

hException

u32

Адрес обработчика ошибок

wParentSegment

size

Сегмент PSP процесса-родителя

JobFileTable

[u8; 20]

Общее расположение пространства памяти

wEnvironment

size

Сегмент переменных среды

dwSsSp

u32

Маска вида SS:SP для входа к последнему вызову INT 0x21

wMaxFilesOpened

u16

Максимальное количество открытых файлов

hRecords

u32

Адрес обработчика ручных записей

bReserved

[u8; 24]

bInterruptOpcode

u8

Опкод прерывания (INT => 0xCD)

wInterruptCode

u16

Номер прерывания.

bReserved

wFirstFcb

u16

Первый закрытый FileControl block уровень

wNextFcb

u16

Перезаписывается, если открыт wFirstFcb

cbArg

u8

Колличество аргументов коммандной строки

bArg

[u8; 127]

Аргументы коммандной строки. Всегда заканчивается на 0x0D

В CP/M и DOS главах упомянались FileControl-блоки, но почему-то ни слуху - ни духу, о них в разборе... Исправляюсь.

Специально выделю два подраздела для неизвестных структур.

File Control Block (FCB)

FCB (File Control Block) в DOS — структура, в которой поддерживается состояние открытого файла. Она находится внутри памяти программы, которая использует файл, а не в памяти операционной системы.
Такое решение позволяет процессу иметь одновременно несколько файлов, если он может выделить достаточно памяти для FCB на каждый файл

В зависимости от версии MS-DOS сама структура потерпела изменения:
Я показываю структуру FCB такой, какая она есть в MS-DOS 2.0, поскольку там присутствуют поля случайного доступа.

#pragma pack(push, 1)
struct FCB_STANDARD {
    unsigned char drive;        // 00: 0 = default, 1=A, 2=B, ...
    char filename[8];           // 01-08: имя файла (лево выровнено, пробелы в конце)
    char extension[3];          // 09-0B: расширение (лево выровнено, пробелы)
    unsigned short current_block; // 0C-0D: текущий блок (начиная с 0)
    unsigned short record_size;   // 0E-0F: размер логической записи в байтах
    unsigned long file_size;      // 10-13: размер файла в байтах
    unsigned short date;          // 14-15: дата (формат: см. выше)
    unsigned short time;          // 16-17: время (формат: см. выше)
    unsigned char reserved[8];    // 18-1F: зарезервировано (зависит от версии)
    unsigned char current_record; // 20:   текущая запись в блоке (0-127)
    
    // MS-DOS 1.25 не имеет поля случайных записей
    unsigned long random_record;  // 21-24: случайная запись (относительно начала файла)
}
#pragma pack(pop)

У блока управления файлом в DOS 2.0 есть расширенный (мне кажется лучше расширяющий) подраздел.

#pragma pack(push, 1)
struct FCB {
    unsigned char signature;     // -7: 0xFF
    unsigned char reserved[5];   // -6 - -2: зарезервировано
    unsigned char attribute;     // -1: атрибут файла
    FCB_STANDARD fcb;             // 00-24: стандартный FCB
}
#pragma pack(pop)

Советую думать, что FCB это своеобразная карточка книги в библиотеке,
а расширенный FCB это пометка [СЕКРЕТНО]. Увы, подробнее об этом в другой раз.

Таблицы процесса (JFT и SFT)

Изначально этот материал я долго не мог уложить в голове, и взял его практически "как есть", без обработки. Но со временем дополнения появились.

Для обеспечения доступа к открытым файлам MS-DOS использует системные таблицы двух типов.

Таблица SFT (полн. "System File Table") содержит записи о всех файлах, в данный момент открытых программами пользователя и самой ОС.

Эта таблица хранится в системной памяти, число записей в ней определяется параметром FILES в файле конфигурации CONFIG.SYS, но не может превышать 255.

Если один и тот же файл был открыт несколько раз (неважно, одной и той же программой или разными), то для него будет несколько записей в SFT.

Каждая запись содержит подробную информацию о файле, достаточную для выполнения операций с ним. В частности, в записи SFT содержатся:

  • копия информации о файле;

  • адрес записи (сектор и номер записи в секторе);

  • текущее положение указателя чтения/записи;

  • номер последнего записанного или прочитанного кластера файла;

  • адрес в памяти программы, открывшей файл;

  • режим доступа, заданный при открытии.

Кроме того, в записи SFT содержится значение счетчика ссылок на данную запись из всех таблиц JFT, речь о которых пойдет позже. Когда этот счетчик становится равным нулю, запись SFT становится свободной, поскольку файл закрыт.

В отличие от единственной SFT, таблицы JFT (полн. "Job File Table")
создаются для каждой запускаемой программы,
поэтому одновременно может существовать несколько таких таблиц.

Теперь к одному из главных вопросов: "Откуда в однозадачной MS-DOS могут взяться одновременно
несколько программ?"
Ответ прост: когда одна программа запускает другую,
то в памяти присутствуют обе.

Таблица JFT имеет простейшую структуру: она состоит из однобайтовых
записей, причем значение каждой записи представляет
собой индекс (номер записи) в таблице SFT.
Неиспользуемые записи содержат значение 0xFF.
Размер таблицы по умолчанию составляет 20 записей (байт),
но может быть увеличен до 255.

Сама JFT находится в PSP области. Если рассматривать поближе
часть ОЗУ где находится процесс, его структура будет такова:

+-----+-----------------------------------------+-----------+-----+
| ... | [argv]; argc.....[1; 6; 2; FF; FF;].... | Программа | ... |
+-----|------------------|----------------|-----|-----------+-----+
      |                  | <--   JFT  --> |     |           |
      |                        20 байт          |           |
      |                                         |           |
      | <-- Начало PSP             Конец PSP -->|           | 
      | <-- Начало             Конец управляемой памяти --> |

Что происходит с файлами при завершении программы,
которая их открыла? Это не важно.

В любом случае ОС должна при завершении программы закрыть
все её файлы. Как ОС узнает, какие файлы следует закрыть?
Достаточно просмотреть таблицу JFT завершаемой программы и
найти там все записи, отличные от 0xFF.

Вывод

Это было большое и насыщенное для меня путешествие в NTVDM (полн. "Windows NT Virtual DOS Machine"), тонкости MS-DOS и её предков, но то, что я нашел на просторах интернета, возможно скоро канет в Лету. Пытаться найти мелочи жизни и как-то уложить их в голову, а потом и сюда.

Я приведу таблицу итогов для .COMманд, и это самая последняя таблица в этом документе.

Характеристики COM

CP/M

DOS

Подпись

нет

нет

Точка входа

везде

везде

Секции

нет

нет

Нулевая страница

PPA/ZPCB

.PSP

Ареал обитания

[0x0000; TPA)

(Program Memory)

В целом, и так понятно, что загрузить программу из MS-DOS 2.0 в чужеродной среде не получится, поскольку нет слоя совместимости системного интерфейса.
Если бы даже архитектуры программ были одинаковы (например сборщик для Intel 8086), то разногласия в вызовах уже бы помешали злодеянию.

Обратная совместимость для CP/M комманд в DOS была, и некоторые поля PSP структуры существуют только для её обеспечения.

Со временем ZPCB/PPA таблица в CP/M-86 станет похожа на .PSP раздел, а сам формат таблицы .PSP станет родителем таблицы релокаций и первых файлов .EXE - MZ-исполняемых файлов.
DOS системы продолжут существовать и станут самостоятельнее, появится BW-DOS с новым форматом исполняемых файлов, а Microsoft и IBM придумают NE-сегментные файлы.

Источники

Комментарии (11)


  1. SIISII
    19.08.2025 14:18

    Небольшое предупреждение! Я буду говорить не просто о том "Как запускаются комманды?"

    В целом статья написана, с точки зрения русского языка, грамотно (что является весьма редким явлением), но вот в её "предисловии" команды почему-то с двумя м :)

    Процессор i8080 (полн. "Intel 8080") был 8-разрядным,соответственно объемы обрабатываемой памяти были не такими уж и большими. Все написанные под эту ОС программы помещались в один файл команды и весили не больше чем 64Кб.

    Пара замечаний. Во-первых, "у них", когда имеются в виду килобайты, принято сокращать их до KB, ну а Kb означают килобиты. Понятно, что в данном случае проблемы с пониманием вряд ли возникнут, но в других ситуациях такое может произойти (скажем, когда указывают ёмкость микросхемы памяти).

    Ну а во-вторых, разрядность процессоров и размеры программ не имеют совсем уж прямой связи. Как, например, транслятор ассемблера в OS/360 мог выполняться в разделе памяти размером порядка 16 килобайт, если он сам суммарно имел куда больший объём и мог транслировать программы, чей размер, по большому счёту, ограничивался только доступным местом на дисках? (Система 360 -- 32-разрядная машина, адрес там был 24-битным, занимая три младших байта слова, т.е. теоретически адресуемый объём памяти достигал 16 Мбайт, но сами машины имели весьма небольшой объём физической памяти; у самой младшей модели 30 он составлял от 8 до 64 Кбайт -- всё ж середина 1960-х).

    Так что "помещались в один файл" -- это именно особенности CP/M, а не безусловная необходимость для 8-разрядного процессора.

    И, кстати, были же оверлейные программы, суммарный размер кода которых мог существенно превосходить 64 Кбайта. Это сейчас про оверлеи, наверное, мало кто помнит :)


    1. art2021 Автор
      19.08.2025 14:18

      Спасибо, буду разбираться дальше. Про оверлеи в следующий раз будет написано однозначно.


  1. blueboar2
    19.08.2025 14:18

    Как-то странно, автор пишет про CP/M, потом про DOS, а в выводе - погружение в NTVDM. Это, конечно, слой совместимости со старыми системами, но о нем вообще раньше ни слова не было, откуда оно взялось?


    1. art2021 Автор
      19.08.2025 14:18

      Спасибо! Постараюсь в следующий раз при вычитке замечать такое


      1. art2021 Автор
        19.08.2025 14:18

        Так-то весь интерес правда с NTVDM появился. Я просто об этом в статье ничего не указал, и в конце лучше бы не писал про это


  1. Jijiki
    19.08.2025 14:18

    а как же устройство терминала, оно там было? комманды и вся обвязка на минимальной ОС может (по моему мнению должна быть обвязана вокруг терминала)

    тоесть можно изучать ОС начиная с терминала например PTY(примитивный VT convention - escape sequences ANSI - шрифт/стили, положение курсора, очистка) - цель получить сессию с привилегиями пользователя, чтобы получить доступ к stdin/stdout/stderr - тоесть системные потоки этого родителя с привилегиями пользователя через командную оболочку

    а уже терминал запускает оболочку - sh, csh и тд

    чтобы видеть привествие )

    PTY Slave: /dev/pts/2
    You can install extra packages for FreeBSD by using the ports system.
    If you have installed it, you can download, compile, and install software by
    just typing
    
            # cd /usr/ports/<category>/<portname>
            # make install && make clean
    
    as root.  The ports infrastructure will download the software, change it so
    it works on FreeBSD, compile it, install it, register the installation so it
    will be possible to automatically uninstall it, and clean out the temporary
    working space it used.  You can remove an installed port you decide you do not
    want after all by typing
    
            # cd /usr/ports/<category>/<portname>
            # make deinstall
    
    as root.
    
    например )


    1. SIISII
      19.08.2025 14:18

      В минимальной ОС терминала может не быть вообще -- он не всегда нужен (да и не только в минимальной). Во всяком случае, терминал в привычном понимании.

      И уж точно изучать ОС с терминала -- путь неверный. Хотя б потому, что терминал "стоит сверху" многих фундаментальных вещей типа управления памятью, управления процессами/потоками, управления вводом-выводом... А "оболочка" -- просто прикладная (по своему месту в системе, хотя и не по функциям) программа


      1. Jijiki
        19.08.2025 14:18

        начал изучать сам с устройства передачи команд через терминал, сделал прототип(pty-+sh получил всё что хотел и сессию и историю и всё что даёт терминал с вводом пароля ) и понял что это хороший путь для изучения полной ОС, потомучто минимальная ОС, если запустит приглашение и в ней будет уже всё обвязано по привилегиям и сигналам/потокам, начиная от старта биоса оптимальный путь - запускать терминал после инициализации оборудования, и дать возможность видео ускорения, тоесть запуска видео драйверов(я просто так для себя понял, если ошибся - понял)

        например на OpenIndiana сегодня до сих пор есть терминал тоже

        немного по сабжу


  1. kmatveev
    19.08.2025 14:18

    Отличная статья. Надеюсь, что автор простит меня, если я немного подушню.

    На всякий случай, команда ld (полн. "LOAD") выполняется как mov из IA-32, а не как lea 

    Для синтаксиса с меткой ld reg, label она выполняется именно как lea, то есть загружает именно адрес, а не значение. MASM-синтаксис для mov reg, label загружал значение, хранящееся в памяти по метке.

    ОС загружает бинарный образ .COM файла начиная с адреса 0x0100. Именно благодаря ORG 100h комманде процессору.

    Нет. Директива ORG указывает ассемблеру, что метки нужно пересчитывать в адреса таким способом, будто код, располагающийся после директивы ORG, размещён по адресу, указанному в этой директиве. А CP/M загружает бинарный образ .COM файла просто всегда с адреса 0x100. И, что очень важно, этот адрес и является точкой входа (не увидел упоминания этого факта).

    И так, идея комманды не меняется. .COM это все еще PIE-монолит (исполняемый файл независящий от точки входа).

    Эээ, вообще PIE означает "position-independent executable" (исполняемый код, не привязанный к адресу загрузки) и к COM-файлам никакого отношения не имеет ни в CP/M, ни в MSDOS. Для CP/M файл будет загружен в абсолютный адрес 0x0100, так что нет никакой независимости от адреса загрузки. Для MS-DOS файл будет загружен в какой-то сегмент и тоже по абсолютному смещению 0x0100, сегмент же не важен, за него COM-программа не вылезает. Из-за независимости от сегмента с большой натяжкой COM-файл для MSDOS может считаться PIE. А насчёт "независимости от точки входа" тоже хрень, точка входа всегда по адресу 0x0100.

    Насколько я знаю, идея .COM файлов для MSDOS состояла в том, что бинарным транслятором машинный код для 8080/Z80 превращается в код для 8086, а DOS эмулирует в PSP функционал CP/M, предоставляя переносимость программ без исходников.


    1. art2021 Автор
      19.08.2025 14:18

      очень рад видеть такие комментарии. Это не является духотой. Я учту это и буду разбираться дальше


  1. bolk
    19.08.2025 14:18

    Можно наверное ещё и про TSR рассказать. В них PSP можно было «отдать системе». Это мало пригождалось правда, только сегментацию порождало.

    Плюс выйти из .com можно было и через INT 20h или даже через RET, если мне память не изменяет (на стеке лежал адрес начала PSP, а там записан тот же INT 20h).

    Ещё очень рекомендую разыскать и скачать «Ralf Brown's Interrupt List», библию всех, кто писал под DOS. Он обновлялся, надо искать версию как можно свежее.