Ausführbare Dateien können in Maschinensprache von Hand codiert werden, obwohl es weitaus bequemer ist, Software als Quellcode in einer Hochsprache zu entwickeln, die von Menschen leicht verstanden werden kann. In einigen Fällen kann der Quellcode stattdessen in Assemblersprache angegeben werden, die für den Menschen lesbar bleibt, während sie eng mit Maschinencodeanweisungen verknüpft ist.
Die Hochsprache wird entweder in eine ausführbare Maschinencodedatei oder in eine nicht ausführbare Maschinencodeobjektdatei kompiliert; der äquivalente Prozess auf Assembler-Quellcode heißt Assembly. Mehrere Objektdateien werden verknüpft, um die ausführbare Datei zu erstellen. Objektdateien – ausführbar oder nicht – werden normalerweise in einem Containerformat gespeichert, z. B. ELF (Executable and Linkable Format) oder PE (Portable Executable), das betriebssystemspezifisch ist. Dies gibt dem generierten Maschinencode Struktur, indem er beispielsweise in Abschnitte wie unterteilt wird .text (ausführbarer Code), .daten (initialisierte globale und statische Variablen), und .rodata (schreibgeschützte Daten wie Konstanten und Zeichenfolgen).Ausführbare Dateien enthalten in der Regel auch ein Laufzeitsystem, das Laufzeitsprachfunktionen implementiert (z. B. Aufgabenplanung, Ausnahmebehandlung, Aufrufen statischer Konstruktoren und Destruktoren usw.).) und Interaktionen mit dem Betriebssystem, insbesondere das Übergeben von Argumenten, die Umgebung und das Zurückgeben eines Exit-Status, zusammen mit anderen Start- und Herunterfahrfunktionen wie dem Freigeben von Ressourcen wie Dateihandles. Für C erfolgt dies durch Verknüpfen des crt0-Objekts, das den tatsächlichen Einstiegspunkt enthält und das Einrichten und Herunterfahren durch Aufrufen der Laufzeitbibliothek vornimmt.Ausführbare Dateien enthalten daher normalerweise erheblichen zusätzlichen Maschinencode, der über den direkt aus dem spezifischen Quellcode generierten hinausgeht. In einigen Fällen ist es wünschenswert, dies wegzulassen, beispielsweise für die Entwicklung eingebetteter Systeme, oder einfach zu verstehen, wie Kompilieren, Verknüpfen und Laden funktionieren. In C kann dies geschehen, indem die übliche Laufzeit weggelassen wird und stattdessen explizit ein Linker-Skript angegeben wird, das den Einstiegspunkt generiert und das Starten und Herunterfahren übernimmt, z. B. main
, um zu starten und am Ende den Exit-Status an den Kernel zurückzugeben.