Zu diesem "Fragezeichen-Symbol" das sind meistens Steuerzeichen (siehe ASCII-Code), "moderne" Betriebssysteme stellen diese dann meistens mit einem Fragezeichen-Symbol dar. Auf älteren Betriebssystemen (z.B MS-DOS) bekommt man andere Symbole ausgegeben, so konnte man auch das eine oder andere Spielchen im Textmodus schreiben!: https://theasciicode.com.ar/
Bevor ich deine Frage beantworte will ich dich wegen deinem Code-Stil loben, sehr übersichtlich! :)
Dein erwartetes Ergebnis ist das am Ende des Strings 0 ausgegeben wird, jedoch bekommst als Ergebnis "Müll".
Ausschlagebend ist diese Zeile:
mov [rax+rdi], rsi
Wenn du direkt 30h in rsi gibst, funktioniert das was du willst.Wie du vielleicht weißt ist es bei NASM & FASM so das '[...]' immer auf einen Speicherzugriff hindeutet.
MOV rsi, msg2 ;rsi = Adresse von msg2
MOV al, byte [msg2] ;al= Inhalt von msg2, erstes Byte
MOV rsi, [msg2] ;rsi = Inhalt von msg2, 8 Bytes
Ich bezweifle ob es wirklich nötig ist 8 Byte in rsi zu packen, wenn du doch nur 1 brauchst, aber das ist ein anderes Thema.
JEDOCH pass auf damit:
mov [rax + rdi], rsi
Es besteht immer die Gefahr das du etwas überschreibst das du eigentlich nicht überschreiben willst (aussehr du willst wirklich 8 Bytes überschreiben!).
Ich finde es sehr cool wie du erstmal kleine Projekte umsetzt! Weiter so :)