Assemblersprache - Einrichtung der Umgebung

Dieses Kapitel führt Sie durch die Einrichtung der NASM-Assembler-Entwicklungsumgebung auf einem Linux-System und das Abschließen Ihres ersten Assemblerprogramms.


Linux-Umgebungsvorbereitung

Wenn Sie Windows verwenden, wird empfohlen,WSL (Windows Subsystem for Linux)zu installieren oder eine virtuelle Maschine zu verwenden, um eine Linux-Umgebung zu erhalten.

macOS-Benutzer können Linux in einer virtuellen Maschine installieren oder Docker-Container verwenden.

Alle Beispiele in diesem Tutorial basieren auf demUbuntu/Debian-System. Für andere Distributionen passen Sie bitte die Paketmanager-Befehle entsprechend an.


NASM-Assembler installieren

Installieren Sie NASM auf Ubuntu/Debian-Systemen mit dem apt-Paketmanager:

$ sudo apt update
$ sudo apt install nasm

Überprüfen Sie nach der Installation, ob NASM erfolgreich installiert wurde:

$ nasm -version
NASM version 2.16.01

Wenn Sie die Versionsnummernausgabe sehen, bedeutet dies, dass NASM erfolgreich installiert wurde.


Linker installieren

Der Assembler generiertObjektdateien (.o-Dateien), die nicht direkt ausgeführt werden können.

Sie benötigen einen Linker, um die Objektdatei in eine ausführbare Datei zu konvertieren. Wir verwenden den mit GCC gelieferten Linker:

$ sudo apt install gcc

Alternativ können Sie direkt den GNU-Linker ld verwenden:

$ ld --version

In diesem Tutorial verwenden wir hauptsächlichgcczum linken, da dieser automatisch einige Low-Level-Details verarbeitet und besser für Anfänger geeignet ist.


Debugging-Tool GDB installieren

GDB (GNU Debugger)ist der am häufigsten verwendete Debugger unter Linux, mit dem Sie Programme schrittweise ausführen, Registerzustände anzeigen und Speicherinhalte untersuchen können.

$ sudo apt install gdb

GDB-Installation überprüfen:

$ gdb --version
GNU gdb (Ubuntu 12.1-0ubuntu1) 12.1

Erstes Assemblerprogramm: Hello, example

Erstellen Sie eine neue Dateihello.asmund geben Sie den folgenden Inhalt ein:

Beispiel

; Dateipfad: hello.asm
; Erstes Assemblerprogramm: "Hello, example!" ausgeben
; NASM-Syntax, Linux 32-Bit

section .data                       ; Datenabschnitt: speichert initialisierte Daten
    msg db 'Hello, example!', 0xA    ; String msg definieren, 0xA ist das Zeilenumbruchzeichen
    len equ $ - msg                 ; Stringlänge berechnen: aktuelle Adresse - Startadresse von msg

section .text                       ; Codeabschnitt: speichert ausführbare Anweisungen
    global _start                   ; _start als Programmeinstiegspunkt deklarieren

_start:                             ; Programmeinstieg
    ; Systemaufruf sys_write (4): String an stdout ausgeben
    mov eax, 4                      ; Systemaufruf-Nummer 4 = sys_write
    mov ebx, 1                      ; Dateideskriptor 1 = stdout (Standardausgabe)
    mov ecx, msg                    ; Adresse des auszugebenden Strings
    mov edx, len                    ; Stringlänge
    int 0x80                        ; Interrupt auslösen, um den Systemaufruf auszuführen

    ; Systemaufruf sys_exit (1): Programm normal beenden
    mov eax, 1                      ; Systemaufruf-Nummer 1 = sys_exit
    mov ebx, 0                      ; Rückgabewert 0 = normaler Beendigungsstatus
    int 0x80                        ; Interrupt auslösen, um den Systemaufruf auszuführen

Kompilieren und Ausführen

Der gesamte Kompilierungs- und Ausführungsablauf ist im Diagramm dargestellt:

汇编程序编译运行流程

Verwenden Sie die folgenden Befehle, um dieses Programm zu kompilieren und auszuführen:

$ nasm -f elf32 hello.asm -o hello.o    # 汇编:将 .asm 转为 .o 目标文件
$ ld -m elf_i386 hello.o -o hello       # 链接:将 .o 转为可执行文件
$ ./hello                               # 运行程序
Hello, example!

Der Zweck der drei obigen Befehle jeweils:

SchrittBefehlBeschreibung
1. Assemblierennasm -f elf32 hello.asm -o hello.o-f elf32 legt das Ausgabeformat als 32-Bit-ELF fest, -o gibt den Namen der Ausgabedatei an
2. Linkenld -m elf_i386 hello.o -o hello-m elf_i386 legt den 32-Bit-Linkmodus fest und generiert die ausführbare Datei hello
3. Ausführen./helloFühren Sie das Programm im aktuellen Verzeichnis aus

Mit GCC linken (Empfohlen)

Wenn die ld-Konfiguration in Ihrer Umgebung komplex ist, können Sie gcc zum Linken verwenden, wodurch Details wie die C-Laufzeitumgebung automatisch verarbeitet werden:

$ nasm -f elf32 hello.asm -o hello.o
$ gcc -m32 hello.o -o hello -nostartfiles
$ ./hello
Hello, example!

-nostartfilesDie Option weist GCC an, keinen Standard-Startcode hinzuzufügen, da wir unseren eigenen_startEinstiegspunkt definieren.


Analyse der Codestruktur

Gehen wir das obige Programm Schritt für Schritt durch:

TeilCodeBeschreibung
Deklaration des Datensegmentssection .dataDeklariert das Datensegment, in dem Variablen und Konstanten gespeichert werden
String-Definitionmsg db 'Hello, example!', 0xAdb definiert eine Byte-Sequenz; 0xA ist der ASCII-Code für einen Zeilenumbruch
Längenberechnunglen equ $ - msg$ repräsentiert die aktuelle Adresse; das Subtrahieren der msg-Adresse ergibt die String-Länge
Deklaration des Codesegmentssection .textDeklariert das Codesegment, in dem Anweisungen gespeichert werden
Einstiegsdeklarationglobal _startExportiert _start als globales Symbol; der Linker benötigt dies
Einstiegs-Label_start:Hier beginnt die Programmausführung

int 0x80Dies ist die 32-Bit-Systemaufruf-Anweisung von Linux. Sie löst einen Software-Interrupt aus, der es dem Kernel ermöglicht, den von uns über eax angegebenen Systemaufruf auszuführen. Dies ist die Brücke zwischen Benutzerprogrammen und dem Betriebssystemkernel.


Debugging mit GDB

Fügen Sie während der Kompilierung Debugging-Informationen hinzu und gehen Sie dann mit GDB Schritt für Schritt durch:

$ nasm -f elf32 -g hello.asm -o hello.o       # -g 添加调试信息
$ ld -m elf_i386 hello.o -o hello
$ gdb ./hello
(gdb) break _start                             # 在 _start 处设置断点
(gdb) run                                      # 运行程序
(gdb) stepi                                    # 单步执行一条指令
(gdb) info registers                           # 查看所有寄存器
(gdb) x/s msg                                  # 查看 msg 字符串内容
(gdb) quit                                     # 退出 GDB
GDB-BefehlFunktion
break _startEinen Haltepunkt am Label _start setzen
runDas Programm ausführen, am Haltepunkt anhalten
stepiEine Maschinenanweisung nach der anderen ausführen
info registersAktuelle Werte aller Register anzeigen
x/s 地址Inhalt an der angegebenen Adresse im String-Format anzeigen

Häufig gestellte Fragen

Wenn Sie 32-Bit-Assembly auf einem 64-Bit-System kompilieren, müssen Sie 32-Bit-Kompatibilitätsbibliotheken installieren:sudo apt install gcc-multilib

Wenn ld beim Linken den Fehler "cannot find entry symbol _start" meldet, überprüfen Sie, ob Sie es in Ihrem Code richtig geschrieben habenglobal _startund ob der Label-Name genau übereinstimmt (achten Sie auf den Unterstrich).

Andere Erweiterungen