Скомпилированная программа обычно содержит заголовок, за которым следуют инструкции процессора (то, что вы могли бы назвать «двоичным») + различные другие данные.
Когда вы пытаетесь указать ОС загрузить вашу программу, заголовок будет прочитан ОС, и он используется для проверки того, что исполняемый файл действительно является исполняемым файлом, предназначенным для этой ОС и этой архитектуры. То есть чтобы вы случайно не запускали программу для Linux на Windows или аналогичную.
Заголовок также содержит различные другие биты информации о том, где фактические инструкции ЦП находятся в исполняемом файле, где расположены сегменты данных (текст, строки, графика) и т. Д.
Как только ОС довольна тем, что исполняемый файл является тем, чем должен быть, ОС загрузит различные сегменты из исполняемого файла в память и даст указание CPU запустить запуск сегмента «двоичного кода». Этот код «чистый» в том смысле, что он является прямым кодом сборки процессора.
Однако операционная система может прервать ЦП (например, переключиться на другую программу или просто убить программу из памяти и т. Д.). Так что вокруг этой работающей программы происходит много вещей, и ОС вроде бы «управляет» ею и обеспечивает ее поведение как хорошего мальчика, но сам код, когда он работает, выполняет чистые инструкции процессора как можно быстрее. ... без ОС, которая должна интерпретировать код между ними.
Также обратите внимание, что запущенная программа может вызывать ОС различными способами во время ее работы. Например, запросить у ОС открыть окно на дисплее, открыть сетевое соединение, выделить память и т. Д. Все, что на самом деле происходит, это то, что процессор просто переходит к выполнению кода в другом месте (то есть он переходит от запуска кода в исполняемом файле к выполнению некоторого фрагмента кода в ОС, а затем возвращается назад).
Вот и все в двух словах. Есть много других способов запуска программ. Существуют виртуальные машины, интерпретируемые языки (например, Java или Ruby) и так далее. И все они запускают программы по-разному от традиционных «чисто двоичных» языков, таких как C / C ++, но, надеюсь, это помогло вам понять, как это работает немного лучше.