2015-11-13 112 views
0

所以我的任務是在彙編代碼中編寫一個程序,該程序可以發出語句,接收用戶輸入的字符串。打印該字符串,然後使用cpu堆棧將其反轉並再次打印。這是我到目前爲止。如何在彙編語言中反轉和打印字符串

INCLUDE Irvine32.inc 

.data 
buffer byte 20 DUP(0) 
byteCount DWORD ? 

Question byte "Please enter your name." ,0 
Greeting byte "Hello " ,0 
Statement byte " Here is your name backwards" 

.code 
main proc 


mov edx , OFFSET Question 
call WriteString 
call CRLF 
Call CRLF 

mov edx, OFFSET buffer 
mov Ecx, SIZEOF buffer 
call ReadString 

push edx 
mov EDX ,OFFSET greeting 
Call WriteString 
pop edx 
call WriteString 
Call CRLF 
Call CRLF 

正如你可以看到這成功地接受了用戶輸入的輸入並顯示它,但我真的很努力地試圖扭轉它。

我在這裏試過這些,我從書中從關於反轉字符串的章節複製而來。

; Push the name on the stack. 

mov ecx,nameSize 
mov esi,0 

L1: movzx eax,aName[esi] ; get character 
push eax    ; push on stack 
inc esi 
loop L1 

; Pop the name from the stack in reverse 
; and store it in the aName array. 

mov ecx,nameSize 
mov esi,0 

L2: pop eax    ; get character 
mov aName[esi],al  ; store in string 
inc esi 
loop L2 

Invoke ExitProcess,0 
main endp 
end main 

但我沒有得到輸出。

它說:「喂,(提供yourname這裏)」

它說:「這是倒退你的名字」

香港專業教育學院嘗試過這種每個不同的化身,我可想而之無濟於事。在我的「字符串」在這裏結束

+0

好的倒轉字符串將是你任務的主要部分。你可以向我們展示/告訴我們你嘗試過的不成功的事情嗎? –

+0

您添加的代碼甚至不使用相同的變量名稱。你是否真的試圖將這些代碼集成到你的程序中? –

+0

是的,我改變了所有的參考,以便它會網格化。 –

回答

2

這是違反我的判斷,因爲反向代碼的代碼片段甚至沒有被集成到原始海報創建的代碼中。變量名稱不同。代碼的快速而髒的集成是創建變量nameSize,該變量包含從調用讀取字符串中讀取的字符數。 ReadString(Irvine32庫的一部分)返回寄存器EAX中讀取的字符數。

.data部分添加變量:

nameSize DWORD ? 

EAX寄存器的ReadString移動內容nameSize後。此代碼:

mov edx, OFFSET buffer 
mov Ecx, SIZEOF buffer 
call ReadString 

應該是:

mov edx, OFFSET buffer 
mov Ecx, SIZEOF buffer 
call ReadString 
mov nameSize, eax  ; EAX contains number of characters read into buffer 

中的代碼片段逆轉代碼中刪除掉底部的線,這些都沒有必要,因爲我們做這個程序等結束在我們原來的代碼中。

Invoke ExitProcess,0 
main endp 
end main 

無處不在的串碼逆轉,我們看到變量aName將其更改爲緩衝,因爲這是我們把用戶的名字。將該代碼放入我們的程序中,並使用WriteString在最後打印反轉的緩衝區。該代碼可能類似於:

INCLUDE Irvine32.inc 

.data 
buffer byte 20 DUP(0) 
byteCount DWORD ? 
nameSize DWORD ? 

Question byte "Please enter your name." ,0 
Greeting byte "Hello " ,0 
Statement byte " Here is your name backwards" 

.code 
main proc 

    mov edx , OFFSET Question 
    call WriteString 
    call CRLF 
    Call CRLF 

    mov edx, OFFSET buffer 
    mov Ecx, SIZEOF buffer 
    call ReadString 
    mov nameSize, eax 

    push edx 
    mov EDX ,OFFSET greeting 
    Call WriteString 
    pop edx 
    call WriteString 
    Call CRLF 
    Call CRLF 

    mov ecx,nameSize 
    mov esi,0 

L1: movzx eax,buffer[esi] ; get character 
    push eax    ; push on stack 
    inc esi 
    loop L1 

    ; Pop the name from the stack in reverse 
    ; and store it in the aName array. 

    mov ecx,nameSize 
    mov esi,0 

L2: pop eax    ; get character 
    mov buffer[esi],al  ; store in string 
    inc esi 
    loop L2 


    mov EDX ,OFFSET buffer 
    call WriteString   ; Write the reversed string that is now in buffer 

    exit 
main ENDP 
END 

如果出現鏈接錯誤,則可能無法鏈接到所有必備庫。嘗試添加這些行到你的程序的頂部:

INCLUDE Irvine32.inc 
INCLUDELIB Irvine32.lib 
INCLUDELIB user32.lib 
INCLUDELIB kernel32.lib 

我應該指出,這是扭轉一個字符串,如果你不介意破壞原有的非常低效的方式。通過反轉字符串,可以在堆棧上沒有輔助緩衝區的情況下完成。

+1

通過推入堆棧來反轉16,32或64位整數序列實際上很聰明。然後它就在堆棧上,按照相反的順序從'[esp]'到'[esp + count * size]'。然而,再次彈出它是荒謬的。由於沒有辦法將單個字節推入堆棧('push [m8]'或其他東西),所以這個想法對於字符串來說太糟糕了。如果您一次加載2,4B或8B,並且在推送之前使用'bswap'來反轉這些字節,它將會起作用。 (或者,'movbe'可以隨時加載並交換(Atom,Haswell和Jaguar))。 –

+1

@PeterCordes這是OP試圖整合的代碼(在更新的問題中),並希望幫助完成基礎知識(作業分配)。根據你想要如何定義_合理的努力_,問題是/是邊緣投票結束。如果我提供了我的答案,我想從他們的機構獲得榮譽獎勵;-) –

+0

+ Michael Petch謝謝,但我無法讓你的代碼甚至編譯。我在構建它時遇到了兩個錯誤。 1無法解析的外部和無法解析的外部符號_mainCRTStartup –

0

在高級別:

  • 分配一個「反向」和「文本」緩衝器
  • 閱讀字符串轉換成「文本」
  • 使一個指針在文本的結尾處,複製各個字符到開始時,分別遞減和遞增。
  • 打印新的'反向'緩衝區。

這樣做未分配新緩衝區是可能的,但應避免在一般的,因爲調用系統調用(你需要每個字符後做)

section .data 

prompt  db "Please enter your name: ", 10 
length  equ $ - prompt 
text  times 255 db 0 
buffer  times 255 db 0 

Enter your text 
section .text 
global main 
main: 
    mov rax, 1 
    mov rdi, 1 
    mov rsi, prompt 
    mov rdx, length 
    syscall 

    mov rax, 0 
    mov rdi, 0 
    mov rsi, text 
    syscall 

    mov rcx, rax ; rcx will be the character counter. 
    mov rsi, text ; a pointer to the current character. Start from the beginning. 
    add rsi, rcx 
    dec rsi  ; Remember the 0-index 
    mov rdi, buffer 

;; This subroutine is also SUB-optimal if your teacher demands 
;; performance, look into the advantages of `lea` and a simple 
;; rep;scas loop as well. 
process_loop: 
    mov bl, [rsi]    ; Now copy from back to front 
    mov [rdi], bl 
    inc rdi 
    dec rsi 
    dec rax 
    jnz process_loop 

    mov rax, 1     ; And print the string 
     mov rdi, 1 
     mov rsi, buffer 
     mov rdx, rcx 
     syscall 

exit: 
    mov  rax, 60 
    mov  rdi, 0 
    syscall 
的成本
+0

這是使用NASM語法(顯然使用32位系統調用)的Linux的64位代碼。原始海報使用MASM語法在Windows上使用32位代碼。我不認爲這在OP使用的環境中提供了很多答案。 –

+0

我同意並注意到,我也不認爲這是非常慷慨的初始海報,爲他們提供一個確切的答案,他們可以複製他們的作業。不用說,移植這個邏輯是微不足道的,並且會迫使用戶熟悉這些概念(並且可能學習MASM中的語義,如'byte ptr') –

+0

您是否碰巧看到我的答案是_這違反了我的判斷。我不願意提供的是更有效的就地方法,我希望教授會給予更好的評價。這就是爲什麼在我的結語中我對此發表了評論;)用戶有一個功能正常的反轉功能,只需要整合。不像我寫新代碼的方式(3行) –