执行期间代码崩溃(程序集)

时间:2013-10-09 05:47:53

标签: assembly x86 nasm

代码编译得很好[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

并且我得到此错误“错误:无效的有效地址”

当我改为“byte”

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之前

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

一旦你拨打任何你打电话来获取输入,字符串就包含字符。我们将string的地址移动到esi,将ebx清零,以用作字符数组的索引。 首先,我们从esi + ebx中的指针移动一个字节并将其移动到eax零扩展eax,当我们在它时,它将char的ASCII值移动到eax的低字节,并且将未使用的上部字节清零。然后我们查找带有NULL的{​​{1}}终结符,如果它在当前索引处为零,我们就完成了将值推送到堆栈上。如果value不为0,我们将test推入堆栈并将eax(我们的索引)递增1并继续循环。

ebx

不需要PopChar: push fmtchar push dword [stdout] call fprintf add esp, 4 * 3 dec ebx jnz PopChar 一个值,然后pop它再次作为我们的print函数/宏的参数,因为它已经在堆栈上并且堆栈是LIFO,推送的最后一个字符是准备打印。在这里,您只看到为push推送的2个参数,但我调整了esp,好像我按了3个参数。好吧,我们从堆栈中删除打印的字符,然后准备好下一个字符。我们怎么知道何时停止?我们使用fprintf循环中的ebx中的数字,并将该值减小到0。

输出: enter image description here