2015-11-13 125 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行) –