我必须编写一个程序,该程序读取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 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 :(得分:1)
使用堆栈反转字符串:
可能需要注意的事项:如果堆栈指针变为奇数,则可能会导致问题,因此在这种情况下,可能会先推送一个额外的0字节以保持堆栈对齐。
答案 1 :(得分:1)
嗯......我看到发布的代码存在一些小问题。除了拼写“strin”rong之外,变量aux
和aux2
太小了。如果您要将32位寄存器放入其中,则需要32位 - 4个字节 - resd 1
或resb 4
(两者都可以)。我认为你可能不需要这些变量,但要使它们的尺寸合适。
然后,如果您要在leave
末尾使用asm_main
,则需要从enter 0, 0
开始。我认为卡特博士的所有例子都是这样做的。
您的输入例程看起来会起作用,但会强制用户准确输入25个字符,即使它们有一个较短的“strin”。这样做的好处是你知道你有多少个角色,但不是很灵活。 Carter博士的库提供了一个read_string
,它返回一个以零结尾的字符串。我们可以对此进行stringlen
,但由于我们无论如何都要检查每个角色,我们只能注意零。
然后你似乎在push eax
做得很好。然后你add eax, 1
。咦?看起来你打算eax
同时成为角色和反击者。这不会起作用!
我想到了推动每个角色,计算它,然后检查它是什么。这会将“Hello”变成“olleH”(当我们pop
'时)。还不错,但是当我们到达目的地时它会导致问题(如果我们使用的是零终止字符串)。我决定首先检查字符,仅推送(并计算)非空格(和非零)字符......
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
已经为零。 loop
指令递减ecx
并且如果非零则跳转。如果ecx
已经为零,则递减为0FFFFFFFFh。这循环很多次。在火焰中崩溃!
我这样解决了......
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
显示它,然后干净利落地退出。如果你在后面添加换行符会更好看。
在推送movzx eax, al
之前,您执行eax
。没有伤害,但我们可以push eax
高位字节中的任何内容。弹出它后,只需忽略al
以外的所有内容。你不能只是push al
......
我希望这不太像“为你做” - 我想不出更好的解释方法。有不同的方法来做到这一点。希望这会给你一些如何继续的想法。
编辑:他们不会让我添加评论(?)。试试这个:
enter 0, 0
与push ebp
/ mov ebp, esp
的效果相同。如果第一个参数非零,它将从esp
中减去该数量 - 为局部变量腾出空间。 leave
与mov esp, ebp
/ pop ebp
的效果相同。来自asm_main
的{{1}}函数的Prolog和epilog。请转到示例中的driver.c
。