【问题标题】:Code crashes during execution (Assembly)执行期间代码崩溃(程序集)
【发布时间】:2013-10-15 06:43:20
【问题描述】:

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

【问题讨论】:

  • 使用调试器,通过单步执行机器指令。 PutStr 不是汇编指令。
  • 然后显示宏文件或至少链接到它。
  • 为什么要对字符使用dword 操作? ASCII 字符通常存储为字节。
  • 会不会出错?
  • 我尝试更改它并且我得到“错误:操作码和操作数的无效组合”

标签: assembly x86 nasm


【解决方案1】:

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

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

【讨论】:

  • 它在最后一个反向字符打印到屏幕后立即崩溃,所以我假设循环退出出现问题
  • @chaosmatter:你的意思是cmp AH,0 / jz loop_out而不是cmp AX,0 / jnz loop_in吗? (如果想法是检查任何一个字符是否为 NUL)
  • 想通了,发布在主要 cmets
【解决方案2】:

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

我没有你的宏文件,所以这里我使用了 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 的低字节,并将高字节归零未使用的字节。然后我们用test 寻找NULL 终止符,如果它在当前索引处为零,我们就完成了将值压入堆栈。如果值不为 0,我们将 eax 压入堆栈并将 ebx(我们的索引)加 1 并继续循环。

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

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

输出:

【讨论】:

    猜你喜欢
    • 2011-01-29
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    相关资源
    最近更新 更多