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.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage