2013-10-09 104 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