linux - 组装 NASM x86 - 简单堆栈项目

标签 linux assembly nasm

我正在编写一个子例程来使用堆栈将十进制数字简单地重新打印为字符串,但没有得到我期望的值。当我通过调试器运行它时,我发现我无法将 esi 的值获取到 al。我怀疑我不被允许以我现在的方式使用 esi,但我不确定是否可以通过其他方式做到这一点。此外,我不允许将存储在 edx 中的元素压入堆栈。

子程序代码:

%define STDIN 0
%define STDOUT 1
%define SYSCALL_EXIT  1
%define SYSCALL_READ  3
%define SYSCALL_WRITE 4
%define BUFLEN 256

        SECTION .bss                    ; uninitialized data section
src_str: resb BUFLEN            ; buffer for backwards number
dec_str: resb BUFLEN                    ; number will be converted and put in this buffer
rlen:    resb 4             ; length

    SECTION .text           ; code begins here
    global      prt_dec

    ; Begin subroutine

prt_dec:
    push    eax
    push    ebx         
    push    ecx
    push    edx
    push    esi
    push    edi
    mov     eax, [esp + 28]     ; store the decimal number 4 bytes each for each push, plus the eip
    mov esi, src_str        ; point esi to the backwards string buffer
    mov     edi, dec_str        ; point edi to the new buffer   
        mov     ebx, 10         ; stores the constant 10 in ebx

div_loop:
    mov edx, 0          ; clear out edx
    div     ebx         ; divide the number by 10
    add     edx, '0'                ; convert from decimal to char
    mov [esi], edx      ; store char in output buffer
    inc     esi         ; move to next spot in output buffer
    inc     ecx         ; keep track of how many chars are added
    cmp eax, 0          ; is there anything left to divide into?
    jne     div_loop        ; if so, continue the loop

output_loop:
    add esi, ecx        ; move 1 element beyond the end of the buffer
    mov al, [esi - 1]       ; move the last element in the buffer into al           
    mov [edi], al       ; move it into the first position of the converted output buffer
    inc edi         ; move to the next position of the converted output buffer
    dec ecx         ; decrement to move backwards through the output buffer
    cmp ecx, 0          ; if it doesn't equal 0, continue loop 
    jne output_loop 

print:  
    mov     eax, SYSCALL_WRITE      ; write out string
        mov     ebx, STDOUT
        mov     ecx, dec_str
    mov     edx, 0                
        mov     edx, rlen           
        int     080h

pop_end:
    pop     edi         ; move the saved values back into their original registers
    pop     esi
    pop edx         
    pop ecx
    pop ebx
    pop     eax
    ret

    ; End subroutine

司机:

%define STDIN 0
%define STDOUT 1
%define SYSCALL_EXIT  1
%define SYSCALL_READ  3
%define SYSCALL_WRITE 4


        SECTION .data                   ; initialized data section

lf:     db  10                  ; just a linefeed 

msg1:   db " plus " 
len1 equ $ - msg1

msg2:   db " minus "
len2 equ $ - msg2

msg3:   db " equals "
len3 equ $ - msg3

        SECTION .text                   ; Code section.
        global  _start                  ; let loader see entry point
    extern  prt_dec

_start: 
    mov ebx, 17
    mov edx, 214123
    mov edi, 2223187809
    mov ebp, 1555544444 


    push    dword 24
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    dword 0xFFFFFFFF
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    3413151
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    ebx
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    edx
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    edi
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    ebp
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    2
    call    prt_dec
    add esp, 4

        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg1
        mov     edx, len1
        int     080h

    push    3
    call    prt_dec
    add esp, 4

        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg3
        mov     edx, len3
        int     080h

    push    5
    call    prt_dec
    add esp, 4
    call    prt_lf

    push    7
    call    prt_dec
    add esp, 4

        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg2
        mov     edx, len2
        int     080h

    push    4
    call    prt_dec
    add esp, 4

        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, msg3
        mov     edx, len3
        int     080h

    push    3
    call    prt_dec
    add esp, 4
    call    prt_lf


        ; final exit
        ;
exit:   mov     EAX, SYSCALL_EXIT       ; exit function
        mov     EBX, 0                  ; exit code, 0=normal
        int     080h                    ; ask kernel to take over



    ; A subroutine to print a LF, all registers are preserved
prt_lf:
    push    eax
    push    ebx
    push    ecx
    push    edx

        mov     eax, SYSCALL_WRITE      ; write message
        mov     ebx, STDOUT
        mov     ecx, lf
        mov     edx, 1          ; LF is a single character
        int     080h

    pop edx
    pop ecx
    pop ebx
    pop eax
    ret

最佳答案

我想到的修复(星号表示我确实触及的行),希望从评论中可以清楚地看到我做了什么:

    ...
div_loop:
*   xor     edx, edx    ; clear out edx
    div     ebx         ; divide the number by 10
*   add     dl, '0'     ; convert from decimal to char
*   mov     [esi], dl   ; store char in output buffer
    inc     esi         ; move to next spot in output buffer
    inc     ecx         ; keep track of how many chars are added
*   test    eax,eax     ; is there anything left to divide into?
*   jnz     div_loop    ; if so, continue the loop
* ; (jnz is same instruction as jne, but in this context I like "zero" more)

*   mov     [rlen], ecx ; store number of characters into variable

output_loop:
* ; esi already points beyond last digit, as product of div_loop (removed add)
*   dec     esi         ; point to last/previous digit
    mov     al, [esi]   ; move the char from the div_loop buffer into al
    mov     [edi], al   ; move it into the first position of the converted output buffer
    inc     edi         ; move to the next position of the converted output buffer
    dec     ecx         ; decrement to move backwards through the output buffer
*   jnz     output_loop ; if it doesn't equal 0, continue loop 

print:  
    mov     eax, SYSCALL_WRITE      ; write out string
    mov     ebx, STDOUT
    mov     ecx, dec_str
*   mov     edx, [rlen] ; read the number of digits from variable
    int     080h

    ...

关于linux - 组装 NASM x86 - 简单堆栈项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39923446/

相关文章:

linux - Bash 命令在更改 Path 变量后不起作用

Java/JDBC/Sybase 登录失败 - JZ00L

linux - Perl - 自动将用户名和密码添加到 Linux 系统的脚本

c++ - fpu中的小数计算错误?

windows - 如何将 .asm 文件汇编并链接到 Win32 可执行文件?

assembly - 有什么方法可以从机器代码中获取助记符?

linux - 即使 Switch.pm 模块存在,也无法找到它

linux - 如何修复尝试调试简单的 nasm 汇编程序时出现 "sigsegv"的问题

c - 在 64 位中将 C 与 NASM 链接起来

linux - 如何在 NASM、Linux、32 位中选择对齐方式