В вычислительной технике исполняемый код , исполняемый файл или исполняемая программа , иногда просто называемые исполняемым или двоичным файлом , заставляют компьютер «выполнять указанные задачи в соответствии с закодированными инструкциями », [2] в отличие от файла данных , который должен быть интерпретированы ( анализированы ) программой, чтобы иметь смысл. [3]
Точная интерпретация зависит от использования. Под «инструкциями» традиционно понимаются инструкции машинного кода для физического процессора . [4] В некоторых контекстах файл, содержащий инструкции сценария (например, байт-код ), также может считаться исполняемым.
Исполняемые файлы могут быть закодированы вручную на машинном языке, хотя гораздо удобнее разрабатывать программное обеспечение в виде исходного кода на языке высокого уровня , который может быть легко понятен людям. В некоторых случаях вместо этого может быть указан исходный код на языке ассемблера , который остается удобочитаемым для человека, но при этом тесно связан с инструкциями машинного кода.
Язык высокого уровня компилируется либо в файл исполняемого машинного кода, либо в неисполняемый файл машинного кода — в какой-то объектный файл ; эквивалентный процесс в исходном коде языка ассемблера называется сборкой . Несколько объектных файлов связаны для создания исполняемого файла. Объектные файлы, исполняемые или нет, обычно хранятся в контейнерном формате , таком как исполняемый и связываемый формат (ELF) или переносимый исполняемый файл (PE), который зависит от операционной системы . [5] Это придает структуру сгенерированному машинному коду, например, разделяя его на такие разделы, как .text (исполняемый код), .data (инициализированные глобальные и статические переменные) и .rodata (данные только для чтения, такие как константы и струны).
Исполняемые файлы обычно также включают в себя систему времени выполнения , которая реализует функции языка времени выполнения (такие как планирование задач , обработка исключений , вызов статических конструкторов и деструкторов и т. д.) и взаимодействие с операционной системой, в частности, передачу аргументов, среды и возврат статуса выхода. вместе с другими функциями запуска и завершения работы, такими как освобождение ресурсов, таких как дескрипторы файлов . Для C это делается путем связывания объекта crt0 , который содержит фактическую точку входа и выполняет настройку и завершение работы путем вызова библиотеки времени выполнения . [6]
Таким образом, исполняемые файлы обычно содержат значительный дополнительный машинный код помимо кода, непосредственно сгенерированного из конкретного исходного кода. В некоторых случаях желательно это опустить, например при разработке встроенных систем, или просто чтобы понять, как работают компиляция, компоновка и загрузка. В C это можно сделать, опустив обычную среду выполнения и вместо этого явно указав сценарий компоновщика, который генерирует точку входа и обрабатывает запуск и завершение работы, например, вызывает main
запуск и возвращает статус выхода ядру в конце. [7]
Чтобы быть выполненным системой (например, операционной системой , прошивкой [ нужна ссылка ] или загрузчиком ), исполняемый файл должен соответствовать двоичному интерфейсу приложения системы (ABI). В простых интерфейсах файл исполняется путем загрузки его в память, перехода к началу адресного пространства и выполнения оттуда. [8] В более сложных интерфейсах исполняемые файлы имеют дополнительные метаданные, определяющие отдельную точку входа . Например, в ELF точка входа определяется в e_entry
поле заголовка, которое указывает адрес (виртуальной) памяти, с которого следует начать выполнение. [9] В коллекции компиляторов GNU это поле задается компоновщиком на основе _start
символа. [10]