【问题标题】:Reverse a string in place - NASM x86 Assembly code就地反转字符串 - NASM x86 汇编代码
【发布时间】:2015-02-15 11:17:13
【问题描述】:

我正在尝试在 NASM 中编写代码来反转字符串,但我不断收到段错误。我发现一些人提出了类似的问题,但回答对我没有帮助。

代码如下:

    %include "asm_io.inc"

    segment .data

    prompt1         db      `Enter String: `,0
    prompt2         db      "Reverse: ",0

    segment .bss

    stringlabel     resd    100

    segment .text

    global reverse
    extern printf
    extern scanf

    reverse:

    call    readstring
    call    strlen
    mov     eax, 5
    mov     ebx, stringlabel        ;save first address of the string
                                    ;eax contains the string length
    add     eax, ebx                ;last address of the string
    sub     eax, 1                  ;account for null character

    whileReverse:

    mov     ecx, [eax]              ;save value of last marker into a temp register
    mov     edx, [ebx]              ;save value of first marker into a temp register
    mov     [ebx], ecx              ;save value in ecx to the memory location pointed by ecx
    mov     [eax], edx              ;save value in edx to the memory location pointed by eax
    inc     ebx                     ;increment first marker, i.e,move closer to the centre
    dec     eax                     ;decrement last marker
    cmp     eax, ebx                ;if first marker is larger then the second marker, then swapping is done
    ja      whileReverse

    whileReverseEnd:

    popa
    leave
    ret


    readstring:

    enter   0,0                     ;setup routine
    pusha                           ;push all registers
    mov     eax, prompt1            ;move user input (String) into the register
    call    print_string            ;print prompt  on terminal


    ;READ A BYTE FROM STDIN
    ;this sub-block of code is to read the user input
    ;I found it on the NASM wikibooks site
    ;I have an idea of what may be going on
    ;But I am not sure why all these registers
    ;are being used

    mov     eax, 3                  ;read
    mov     ebx, 0                  ;read from standard input
    mov     ecx, stringlabel        ;address to pass
    mov     edx, 100                ;input length
                                    ;must save the input string
                                    ;in eax (requirement)
    int     0x80                    ;call the kernal
    call    print_string            ;print user input on terminal
    popa
    ret

    strlen:

    enter   0,0
    pusha

    mov     eax, prompt1            ;save the address of the first memory 'block' of stringlabel in eax
    mov     ebx, eax                ;move both markers to the first memory 'block' address

    whileLen:

    mov     cl, [eax]               ;move value from eax to lower ecx
    cmp     cl, 0                   ;look for null value in the current address
    je      whileLenEnd             ;exit loop if null value is found in the current address
    inc     eax                     ;else, increment eax to move on to the next memory location or 'block'
    jmp     whileLen                ;jump back to while loop and repeat

    whileLenEnd:

    sb      eax, ebx                ;subtract the final positions of the markers to calculate the string length must save the string length in eax {requirement)
    pop     ebx
    pop     ecx
    leave
    ret

【问题讨论】:

  • strlen 例程中,您在开始时推送所有寄存器,但最后只弹出ebxecx
  • mov ecx, [eax] 移动四个字节,而您的代码似乎假设它移动一个字节。

标签: assembly x86 segmentation-fault nasm machine-language


【解决方案1】:

将 5 分配给 EAX 会破坏调用 strlen 的目的。只需将其删除。

call    strlen
mov     eax, 5

下一行的注释是错误的。需要减量才能将 EAX 放在字符串的最后一个字符上。

sub     eax, 1                  ;account for null character

您需要将字符视为字节而不是双字。

mov     cl, [eax]  ;save value of last marker into a temp register
mov     dl, [ebx]  ;save value of first marker into a temp register
mov     [ebx], cl  ;save value in ecx to the memory location pointed by ecx
mov     [eax], dl  ;save value in edx to the memory location pointed by eax

此代码不会正确退出程序。调用内核的 EXIT 函数。

whileReverseEnd:

popa
leave
ret

由于readstring 使用enter 0,0,您需要在poparet 之间添加匹配的leave

strlen 中不使用pusha 更容易。这样可以返回EAX!

strlen:
enter   0,0
push    ecx
push    ebx
mov     eax, prompt1  ; <-- Change this to    stringlabel

下一行可能有错字。将 sb 更改为 sub

sb      eax, ebx                ;subtract the final positions 

【讨论】:

    【解决方案2】:
    ;***************************************************
    ;
    ; Reversing a string in 8086 ALP
    ;
    ; code by Akshay Rajput
    ;****************************************************
    
    section .data
    msg db "microprocessor"
    len: equ $-msg
    
    section .bss
    rstring resb 14
    
    section .code 
    global _start
    
    _start:
        %macro write 2
        mov eax,4
        mov ebx,1
        mov ecx,%1
        mov edx,%2
        int 80h
        %endmacro
    
        %macro read 2
        mov eax,3
        mov ebx,0
        mov ecx,%1
        mov edx,%2
        int 80h
        %endmacro
    
        mov esi,msg
        mov ecx,14
        add esi,len-1
        mov edi,rstring
    
    AGAIN:mov eax,[esi]
        mov [edi],eax
        dec esi
        inc edi
        LOOP AGAIN
    
        write rstring,14
    
    
    
        mov eax,1
        int 80h
    

    【讨论】:

    • 为什么你的loop 指令是全大写的,而其他指令都不是?更重要的是,你为什么使用the slow loop instruction at all?但无论如何,您犯了与 OP 相同的错误:您正在加载/存储 4 个字节,因此您覆盖了尚未读取的部分字符串。请参阅 Sep 的答案,该答案已经回答了这个问题。
    • 另外,8086 没有 32 位寄存器。此代码至少需要 80386 才能运行。 (也适用于 32 位 Linux 系统调用。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2020-03-21
    • 2013-10-27
    • 1970-01-01
    相关资源
    最近更新 更多