Linux x86 NASM - Subroutine: Drucken Sie ein Dword aus EAX
Also lerne ich x86 Linux Assembly mit NASM-Syntax (Oh Gott, das nicht schon wieder, ihr denkt alle). Ich versuche, eine Unterroutine zu erstellen, die einfach den Wert in EAX in stdout ausgibt. Der Code wird ohne Fehler ausgeführt und beendet, es wird jedoch nichts gedruckt. Ich kann nicht herausfinden warum. Hier ist zunächst die Datei, in der ich arbeite:
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
add ecx, 47 ;add 47 for ASCII numbers
mov edx, 2 ;double word = 2 bytes
int 0x80
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
Dies wird aus meiner Hauptdatei aufgerufen, die so aussieht (dies ist wahrscheinlich irrelevant, es sei denn, ich vermisse etwas Drastisches).
segment .data
hello db "Hello world!", 0
newline db 0xA
len equ $ - hello
len2 equ $ - newline
segment .text
extern print_nl
extern print_eax_val
global main
main:
enter 0,0
call print_nl
mov eax, 1
call print_eax_val
mov ebx, 0 ;exit code = 0 (normal)
mov eax, 1 ;exit command
int 0x80 ;ask kernel to quit
print_nl
ist nur ein weiteres Unterprogramm, das eine neue Zeile definiert und druckt. Dies wird erfolgreich ausgeführt und druckt eine neue Zeile wie erwartet.
Hat das Problem mit dem Längenparameter für my zu tun?sys_write
Anruf? Ich gebe es 2, das ist die Größe einesdword
, das ist die Größe der beidenEAX
registrieren und meineto_print
Etikett, bei dem ich reserviert haberesd 1
. Ich habe aus Verzweiflung versucht, die Länge auf 1, 4, 8, 16 und 32 zu ändern ... Es hat nichts funktioniert.
BEARBEITEN: Für alle, die sich fragen, ist hier, wie ich den Code repariert habe: (Ich werde Sternchen auf Zeilen setzen, die ich geändert habe):
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
**** add dword [to_print], 48
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
**** mov ecx, to_print
mov edx, 2
int 0x80
**** sub dword [to_print], 48
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
Grundsätzlich gilt,ecx
muss das enthaltenAdresse des Blocks, den Sie drucken möchten, NICHT der Wert selbst. Dies wird, wie in der ausgewählten Antwort ausgeführt, der Fall seinnur Arbeit, wenn eax im Bereich von 0-9 liegt.
BEARBEITEN 2: Also war ich ein bisschen verwirrt über den 2. Parameter für sys_write (der inedx
). Ich denke, es bezieht sich nur auf eine Anzahl von Bytes. Also für einedword
, wie ich es benutze, wäre es angebracht, dort 4 zu verwenden, da ein Doppelwort 4 Bytes oder 32 Bits hat. Ich vermute, es hat funktioniert, weil x86 Little-Endian ist. Also im Speicher der Hex-Wert vonto_print
würde so aussehen:
90 00 00 00
Und mit einer angegebenen Länge von zwei erhält sys_write:
90 00
So wird der Wert zum Glück nicht verfälscht.
Ich habe später den Code zum Speichern geändertto_print
stattdessen als Byte mitresb 1
und Zugriff darauf mitbyte
anstattdword
... Ein Byte ist in Ordnung hier, weil ich weiß, dass ich nicht geben werdeto_print
ein Wert über 9.