2013-10-09 106 views
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

+0

使用调试器,通过步入机器指令。 'PutStr'不是一个汇编指令。 –

+0

使用宏文件 – BKreger

+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 
+0

在最后的反转字符被打印到屏幕上后,它会立即崩溃,所以我假设循环出口出了问题 – BKreger

+0

@chaosmatter:你不是指'cmp AH,0/jz loop_out'而不是'cmp AX,0/jnz loop_in'? (如果主意是检查其中的任何一个角色是否为NUL) – Michael

+0

会计算出来,发布在主要评论 – BKreger

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,同时我们将它移动到char的ASCII字符的低位字节中,并将较高的未使用字节清零。然后我们查找NULL终止符test,如果它在当前索引处为零,我们将把值推入堆栈。如果值不是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个参数。那么我们从堆栈中移除打印的字符,并且下一个字符已准备就绪。我们如何知道何时停止?我们使用数ebx从我们PushChar循环,降低该值,直至为0。

输出: enter image description here