簡體   English   中英

Linux x86 NASM - 子程序:從EAX打印雙字

[英]Linux x86 NASM - Subroutine: Print a dword from EAX

所以我正在學習使用NASM語法的x86 Linux程序集( 哦,上帝,不是這個 ,你們都在考慮)。 我正在嘗試創建一個子程序,只需將EAX中的值打印到stdout即可。 代碼運行並退出而沒有錯誤,但沒有打印。 我無法弄清楚為什么。 首先,這是我正在處理的文件:

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

這是從我的主文件調用的,看起來像這樣(這可能是無關緊要的,除非我遺漏了一些激烈的東西)。

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只是另一個定義和打印換行符的子例程。 這成功運行並按預期打印新行。

該問題是否與我的sys_write調用的length參數有關? 我給它2,這是dword的大小,它是EAX寄存器和我的to_print標簽的大小,我用resd 1保留。 我試圖將絕對長度改為1,4,8,16和32 ......沒有任何效果。

編輯:對於任何想知道的人,這里是我修復代碼的方法:(我會在我更改的行上添加星號):

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

基本上, ecx必須包含要打印的塊的地址 ,而不是值本身。 正如在所選答案中所指出的,這在eax在0-9范圍內時才有效。

編輯2 :所以我對sys_write的第二個參數(存儲在edx中的那個)有點困惑。 我認為它只是指了一些字節。 所以對於dword ,正如我所使用的那樣,在那里使用4是合適的,因為雙字是4字節,或32位。 我猜它有效,因為x86是小端的。 所以在內存中, to_print的十六進制值如下所示:

90 00 00 00

並且提供的長度為2,sys_write獲得:

90 00

所以值得幸運的是不會被破壞。

我后來更改了代碼以將to_print存儲為字節,使用resb 1並使用byte而不是dword訪問它...這里的字節很好,因為我知道我不會給to_print一個大於9的值。

我在匯編程序中非常生疏,但看起來ECX包含值48,它應該包含要寫入的緩沖區的地址。

我認為你在print_eax_val中的print_eax_val是采用EAX的二進制值,將ASCII偏移量添加到數字0 (應該是48,而不是47),然后打印該單個字符。 要做到這一點,在存儲前值增加48 to_print ,把地址to_print在ECX,長度(EDX)設置為1,因為你寫的只有一個字符。

現在請記住,這僅適用於0x0000和0x0009之間的EAX值。 當你超過9時,你會得到其他ASCII字符。

解釋如何獲取EAX的任意二進制值並將其轉換為可打印的十進制字符串遠遠超出了SO的范圍。

write系統調用需要打印字符緩沖區,由%ecx指向,其長度由%edx 另一方面,像%eax這樣的寄存器包含一個32位整數。

因此,如果您確實要打印%eax ,則需要先將該整數轉換為字符序列。 您可以將其轉換為ASCII十進制,十六進制或任何其他您喜歡的基礎,但您需要將其轉換為字符。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM