String 如何在nasm中反转字符串中的每个单词?
我必须写一个程序,读取25个字符的字符串,并返回相同的字符串,每个单词的字母在asm语言中颠倒 例如:String 如何在nasm中反转字符串中的每个单词?,string,assembly,nasm,reverse,String,Assembly,Nasm,Reverse,我必须写一个程序,读取25个字符的字符串,并返回相同的字符串,每个单词的字母在asm语言中颠倒 例如: Input >> Hello world. How are you? Output >> olleH .dlrow woH era ?uoy 这就是我所做的: %include "asm_io.inc" segment .data prompt1 db "Insert the strin: ", 0 ; don't forget nul termi
Input >> Hello world. How are you?
Output >> olleH .dlrow woH era ?uoy
这就是我所做的:
%include "asm_io.inc"
segment .data
prompt1 db "Insert the strin: ", 0 ; don't forget nul terminator
prompt2 db "The string is: ", 0
prompt3 db "The reverse string is: ", 0
segment .bss
vector resb 25
vectorInvert resb 25
aux resb 1
aux2 resb 1
segment .text
global asm_main
asm_main:
mov eax, prompt1 ; print out prompt
call print_string
mov edi, vector ;vetor e do tipo byte
mov ecx, 25
read:
call read_char
stosb
loop read
mov eax, 0
mov edx, 0
mov esi, vector
mov ecx, 25
stack:
mov al, [esi]
cmp al, " "
jz stack2
movzx eax, al
push eax
add eax, 1
add esi, 1
loop stack
stack2:
mov [aux], ecx
mov [aux2], eax
mov ecx, 25
sub ecx, eax
mov edi, vectorInvert
lp:
pop eax
add edx, 1
mov [edi], eax
add edi, 1
loop lp
add eax, 1
add edx, 1
add esi, 1
add edi, 1
mov ecx, [aux]
mov eax, [aux2]
cmp eax, 25
jz out
jnz stack
out:
mov eax, prompt3
call print_string
mov edi, vectorInvert
mov ecx, 25
print:
lodsb
call print_char
loop print
call print_nl
leave
ret
我被困在那里,我不知道如何继续前进。我真的非常感谢您对这段代码的帮助。
我在这里使用这个库:drpaulcarter.com/pcasm/linux-ex.zip
(请注意,我在汇编方面完全是新手。)使用堆栈反转字符串:
可能需要注意的事项:如果堆栈指针变为奇数,可能会导致问题,因此在这种情况下,可能会先推送额外的0字节以保持堆栈对齐。好吧。。。我看到发布的代码有一些小问题。除了拼写“strin”rong,变量
aux
和aux2
太小。如果要在它们中放入32位寄存器,则它们必须是32位-4字节-resd1
或resb4
(两者都可以)。我想你可能不需要这些变量,但要使它们的大小合适
然后,如果要在asm_main
末尾使用leave
,则需要从开始,输入0,0
。我认为卡特博士所有的例子都是这样的
您的输入例程看起来可以正常工作,但强制用户准确输入25个字符,即使它们的“strin”较短。这样做的好处是你知道你有多少个字符,但不是很灵活。卡特博士的库提供了一个读取字符串
,它返回一个以零结尾的字符串。我们可以在这上面做一个stringlen
,但是因为我们无论如何都要检查每个字符,我们可以只看零
然后,通过推送eax
,您似乎做得很好。然后添加eax,1。嗯?看起来您希望eax
既是字符又是计数器。这行不通
我想把每个角色按一下,数一数,然后检查一下是什么。这会使“Hello”变成“olleH”(当我们弹出时)。还不算太糟,但是当我们到达末尾时(如果我们使用的是以零结尾的字符串),它会导致一个问题。我决定先检查字符,只推(和计数)非空格(和非零)字符
mov esi, string
mov edi, reverse
nextword:
xor ecx, ecx ; counter - per word
pushloop:
lodsb
cmp al, ' '
jz poploop
cmp al, 0
jz cleanuploop
push eax ; if not, save it (plus garbage)
inc ecx
jmp pushloop
poploop:
pop eax ; including garbage
stosb ; store al only, ignoring garbage
loop poploop
mov al, ' '
stosb
jmp nextword
cleanuploop:
pop eax
stosb
loop cleanuploop
mov al, 0 ; zero-terminate our string for "print_string"
stosb
这“有效”。你看到缺陷了吗?如果讨厌的用户输入一个空格作为第一个字符(或最后一个,或什么也不输入),我们将进入poploop
(等),而ecx
已经为零。循环
指令递减ecx
,如果非零则跳转。如果ecx
已经为零,它将递减到0ffffffh。这循环了很多次。在火焰中坠毁
我是这样解决的
mov esi, string
mov edi, reverse
nextword:
xor ecx, ecx
pushloop:
lodsb
cmp al, ' '
jz poploop
cmp al, 0
jz cleanuploop
push eax
inc ecx
jmp pushloop
poploop:
jecxz skippop ; bail out if ecx is zero
pop eax
stosb
loop poploop
skippop:
mov al, ' '
stosb
jmp nextword
cleanuploop:
jecxz skippop2
pop eax
stosb
loop cleanuploop
skippop2:
mov al, 0
stosb
显示它,当然要干净地退出。如果你在后面加一条新线,看起来会更好
在按下eax
之前,请执行movzx-eax,al
。没有问题,但是我们可以推送eax
上面字节中的任何内容。只要在弹出后忽略所有内容,除了al
。正如您所知道的那样,您不能只推al
我希望这不太像“为你做”——我想不出更好的解释。有不同的方法可以做到这一点。希望这将给你一些想法如何继续
编辑:他们不允许我添加评论(?)。请尝试以下方法:
输入0,0
的操作与推ebp
/移动ebp,esp的操作相同。如果第一个参数非零,它将从esp
-中减去该值,为局部变量留出空间<代码>离开
与移动esp、ebp/弹出ebp
的操作相同。从driver.c
调用的asm\u main
函数的序言和结束语。查看示例中的skel.asm
。这是什么处理器?处理器是IntelI?我正在从这里使用库:可能是重复的,你不能推送一个字节<代码>推送r16可在所有模式下使用(包括64位),因此您可以在推送之前加载一个字并将其交换(使用rol ax,8
)。或者展开加载并检查循环,在寄存器中用移位建立2或4B,这样您就可以推送该值。或者根本不使用实际的push
指令。在运行时向下调整堆栈指针是一个很好的建议,可以在不首先遍历输入的情况下动态分配堆栈内存(strlen
)。