0

代码编译得很好[ NASM]

但是一旦我输入我的第一个值,它就会崩溃

我不知道出了什么问题,目标是输入一个字符串并输出字符串的反转,如果用户说是('Y'或'y'),则一直循环重复

**.DATA
; Initialized Data Definitions 

strlength      EQU     40
PromptStr      dd      "Please input a string (must be less than 40 characters long): ", 0
OutputStr      dd      "The reverse string is: ", 0
AgainStr       dd      "Would you like ot try again? ('Y' or 'y' for yes): ", 0 

.UDATA
; Uninitialized Data Definitions 

string         resb    strlength

.CODE
; Program Code

.STARTUP

nwln                    ; start output at a new line
PutStr      PromptStr
nwln
while:
    GetStr              string
    mov                 EBX, string

    loop_in:
        push            dword[EBX]
        add             EBX, 4
        cmp             dword[EBX], 0
        jnz             loop_in

    loop_out:
        XOR             EBX, EBX
        pop             EBX
        PutCh           [EBX]
        cmp             dword[EBX], 0
        jnz             loop_out

    nwln
    PutStr              AgainStr
    GetStr              EBX
    mov                 AL, [EBX]
    cmp                 AL, 'Y'
    jz                  while
    cmp                 AL, 'y'
    jz                  while

    Pause


.EXIT**

我将第一个循环更改为

loop_in:
        mov             AL, [EBX]
        push            byte[AL]
        add             EBX, 4
        cmp             byte[AL], 0
        jnz             loop_in

我收到此错误“错误:无效的有效地址”

当我更改为“字节”时

loop_in:
        push            byte[EBX]
        add             EBX, 4
        cmp             byte[EBX], 0
        jnz             loop_in

我收到“错误:操作码和操作数的无效组合”

对于行 {add EBX, 4}

所以我改变了

loop_in:
        push            EBX
        inc             EBX
        cmp             byte[EBX], 0
        jnz             loop_in

    loop_out:
        XOR             EBX, EBX
        pop             EBX
        PutCh           [EBX]
        cmp             byte[EBX], 0
        jnz             loop_out

现在它编译了,我做到了这一点

Please input a string (must be less than 40 characters long):
asdf
fdsaêë

在它崩溃到 Windows 之前

4

2 回答 2

0

也许这样的事情可以工作:

loop_in:
    mov             AX, [EBX]
    push            AX         ; move two characters to the stack
    inc             EBX
    inc             EBX
    cmp             AX, 0
    jnz             loop_in
    cmp             AL, 0
    jnz             loop_in    ; two end-of-string checks,
                               ; because we push two characters


loop_out:
    pop             AX
    PutCh           AH
    PutCh           AL
    dec             EBX
    dec             EBX
    cmp             EBX, string
    ja              loop_out
于 2013-10-09T07:03:50.363 回答
0

你是如何“编译”这个的,因为我们不编译汇编源代码,我们汇编并可选地链接。

我没有你的宏文件,所以在这里我使用了 C 库中的一些函数,但它们应该都是一样的:

    push    dword [stdin]
    push    MAX_INPUT
    push    string
    call    fgets                           
    add     esp, 4 * 3

    ;~ fgets adds the NL char to string, replace with NULL
    push    string
    call    RemoveNL

    mov     esi, string
    xor     ebx, ebx
PushChar:
    movzx   eax, byte[esi + ebx]
    test    eax, eax
    jz      PopChar
    push    eax
    inc     ebx
    jmp     PushChar

PopChar:
    push    fmtchar
    push    dword [stdout]
    call    fprintf                         
    add     esp, 4 * 3    
    dec     ebx
    jnz     PopChar

    jmp     Done

RemoveNL:
    mov     esi, [esp + 4]
    xor     ecx, ecx
    dec     ecx
.FindNL:
    inc     ecx
    cmp     byte [esi + ecx], 10
    jne     .FindNL
    mov     byte [esi + ecx], 0
    ret     4

现在解释一下:

    mov     esi, string
    xor     ebx, ebx
PushChar:
    movzx   eax, byte[esi + ebx]
    test    eax, eax
    jz      PopChar
    push    eax
    inc     ebx
    jmp     PushChar

一旦你调用任何你调用的东西来获取输入,字符串就会包含字符。我们将stringinto的地址esi移出,置零ebx以用作字符数组的索引。首先,我们从 esi + ebx 中的指针移动一个字节,并将其移动到eax零扩展eax,当我们在它处时,它将 char 的 ASCII 值移动到 eax 的低字节,并将高位未使用的字节清零。然后我们寻找NULL终止符,test如果它在当前索引处为零,我们就完成了将值压入堆栈。如果 value 不为 0,我们压入eax堆栈并将ebx(我们的索引)加 1 并继续循环。

PopChar:
    push    fmtchar
    push    dword [stdout]
    call    fprintf                         
    add     esp, 4 * 3    
    dec     ebx
    jnz     PopChar

不需要pop一个值,然后push它再次作为我们的打印函数/宏的参数,因为它已经在堆栈上并且堆栈是 LIFO,最后一个被压入的字符已准备好打印。在这里,您只看到推送了 2 个参数,fprintf但我调整了 esp,就好像我推送了 3 个参数一样。好吧,我们从堆栈中删除打印的字符,下一个字符就准备好了。我们怎么知道什么时候停止?我们使用循环中的数字ebxPushChar减小该值直到它为 0。

输出: 在此处输入图像描述

于 2013-10-10T02:47:32.840 回答