簡體   English   中英

為什么這個簡單的匯編程序不返回數字?

[英]Why doesn't this simple assembly program return a number?

為什么這個簡單的匯編程序不返回數字?

我正在嘗試使它打印12進制,但其打印亂碼。

global _start

section .text

_start:

    mov eax, 0x4
    mov ebx, 0x1
    mov ecx, var1
    mov edx, 2
    int 0x80

    ;exit the program gracefully
    mov eax, 0x1
    mov ebx, 0x5
    int 0x80

section .data

    var1:   db 0x12

您遇到的主要絆腳石試圖將0x12 (ASCII 18)的寫入stdout 快速檢查ASCII圖表將發現此值不可打印。 在匯編中,您只能將字符寫入stdout 這就是說,當面對一個數字值時 ,您必須將該值分成數字,然后將數字轉換為ASCII表示形式(通過將'0'0x3048位十進制加)。

這與以C或任何其他語言將數字手動轉換為字符串沒有什么不同。 您基本上可以將原始數字重復除以10 ,每次將剩余的數字作為數字保存到緩沖區中,然后以相反的順序寫出緩沖區,以將數字的ASCII表示形式寫到stdout (SO上有很多示例)。

在看一個將所有數字分隔到緩沖區並將它們寫入stdout的示例之前,讓我們僅介紹示例中的一些基礎知識並使其打印任何內容。 您需要牢記在腦中的匯編的第一個概念是,匯編中的所有標簽(變量)都指向一個內存地址,而不是數字值。 在裝配中分配標簽時,例如:

var1  db 0x12

var1指向的存儲位置存儲一個單字節數據,其值為12-hex var1是指向該內存位置的指針。 在nasm中,如果要在該位置上操作/或引用該 ,則必須通過將指針括在[ ]來將指針解除引用到地址(就像在C中使用*var1解除引用指針一樣)。

鞏固的下一個概念是sys_write (syscall 4)期望在ecx存儲的起始內存地址而不是值。 然后,它將edx數據字節寫入ebx (1- stdout )中存儲的文件描述符中。 mov荷蘭國際集團的地址var1edx將使我們能夠在解引用該地址的值通過對操作[edx] 要將單個數字轉換為ASCII值,請在其上添加'0' (或0x30),但是如果僅在[edx]添加'0' ,結果將是什么? (當前值0x12 (18)+ 0x30 (48)= 0x42 (66)-恰好是ASCII'B 'B'

(我們還將作弊,並在var1的末尾添加一個newline0xa ),並將其0xa 2個字節,這樣我們就不必再為單獨的調用弄亂了。)

將其與您的示例放在一起將導致:

section .text

    global _start

_start:

        mov     eax, 4              ; linux sys_write
        mov     ebx, 1              ; stdout
        mov     ecx, var1           ; mov address of var1 to ecx
        add     byte [ecx], 0x30    ; add '0' to first byte of var1
        mov     edx, 2              ; number of chars to print
        int     0x80                ; syscall

        mov     eax, 0x1            ; __NR_exit 1
        xor     ebx, ebx            ; exit code of 0
        int     0x80

section .data

    var1  db 0x12, 0xa  ; ASCII 18 (non-printable) with newline

編譯並運行該程序將導致:

$ ./convert
B

現在我們來看一個完整的示例,它將存儲在var1處的值的每個數字分開,然后將0x12 (十進制18)的每個數字打印到stdout然后newline (輸出轉換為十六進制表示形式的工作就交給您了-您可以在網上搜索幾個示例, 然后就會想到int 80h.org 。)

nasm中的一個簡單示例是:

section .text

    global _start

_start:

        mov     edi, result     ; address of buffer in destination index
        xor     eax, eax        ; zero out eax

        mov     al, [var1]      ; put the value of var1 in al to divide
        mov     bl, 10          ; base 10 divisor to find remainder

        ; separate remainder digits into result buffer
 remloop:
        div     bl              ; divide current value by 10
        mov     [edi], ah       ; move the remainder to result
        cmp     al, 0           ; is the quotient zero?
        je      printchar       ; if it is we are done
        xor     ah, ah
        inc     edi             ; move offset in result string (note digits
        jmp     remloop         ; of answer are stored in reverse order)

    printchar:
        add    byte [edi], 0x30 ; add ascii '0' to digit to get printable char
        mov     eax, 4          ; linux sys_write
        mov     ebx, 1          ; stdout
        mov     ecx, edi        ; point to current digit
        mov     edx, 1          ; number of chars to print
        int     0x80            ; syscall
        dec     edi             ; point to next digit
        cmp     edi, result     ; are we past the final digit?
        jge     printchar       ; if not, keep printing to stdout

        ; print newline
        mov     eax, 4          ; linux sys_write
        mov     ebx, 1          ; stdout
        mov     ecx, newline    ; address of newline
        mov     edx, 1          ; number of chars to print
        int     0x80            ; syscall

        ; exit the program gracefully
        mov eax, 0x1            ; __NR_exit 1
        mov ebx, 0x5            ; exit code of 5
        int 0x80

section .data

    var1  db 0x12       ; ASCII 18 (non-printable)
    result times 8 db 0 ; 8 byte buffer for result
    newline db 0xa      ; newline character

如果您構建代碼:

nasm -f elf -o convert.o convert.asm
ld -m elf_i386 -o convert convert.o

然后,您可以顯示0x1218 ASCII的ASCII輸出:

$ ./convert
18

有關匯編的出色Web參考,請參見匯編語言編程的藝術 閱讀。 所有的。 就是那樣 盡管它主要是為8086編寫的,但所有原理都可100%適用於當前的匯編編程。 唯一的區別是x86_64的寄存器大小,調用約定和系統調用號。

暫無
暫無

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

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