我必须编写一个汇编程序,从用户在键盘上键入的五个不同字符串中插入字符,例如,如果我有:
- S1: "Hello">
- S2: "Bye"> S3: "Apple">
- S4: "Car">
- S5: "Tree">
结果为:" hbacteyparlepreloe">
这就是我目前所做的,它可以从相同大小的字符串中插入,我不知道该怎么做才能让它对不同大小的字符串起作用,如果有更好的方法。我将非常感谢你的帮助,因为这是我的第一个汇编程序之一。
segment .data
instruccion db 'Ingrese 5 cadenas de igual longitud no mayores a 20 caracteres:',0x0A
lonI EQU ($-instruccion)
segment .bss
contador resb 1
cad1 resb 20
cad2 resb 20
cad3 resb 20
cad4 resb 20
cad5 resb 20
cad6 resb 101
segment .text
global _start
_start:
mov edx,lonI
mov ecx,instruccion
call imprimir
mov edx,20d
mov ecx,cad1
call leer
mov ecx,cad2
call leer
mov ecx,cad3
call leer
mov ecx,cad4
call leer
mov ecx,cad5
call leer
mov edi,cad1
mov ecx,255
mov eax,0Ah
repne scasb
mov eax,255
inc ecx
sub eax,ecx
mov edi,cad6
mov ecx,eax
mov ebx,0
ciclo:
mov esi,cad1
cld
mov edx,ecx
mov ecx,ebx
cmp ebx,0
jne THEN1
je ELSE1
THEN1:
lodsb
loop THEN1
ELSE1:
movsb
mov esi,cad2
cld
mov ecx,ebx
cmp ebx,0
jne THEN2
je ELSE2
THEN2:
lodsb
loop THEN2
ELSE2:
movsb
mov esi,cad3
cld
mov ecx,ebx
cmp ebx,0
jne THEN3
je ELSE3
THEN3:
lodsb
loop THEN3
ELSE3:
movsb
mov esi,cad4
cld
mov ecx,ebx
cmp ebx,0
jne THEN4
je ELSE4
THEN4:
lodsb
loop THEN4
ELSE4:
movsb
mov esi,cad5
cld
mov ecx,ebx
cmp ebx,0
jne THEN5
je ELSE5
THEN5:
lodsb
loop THEN5
ELSE5:
movsb
mov ecx,edx
inc ebx
loop ciclo
mov eax,0Ah
stosb
mov edx,101d
mov ecx,cad6
call imprimir
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
leer:
mov ebx,0
mov eax,3
int 0x80
ret
imprimir:
mov ebx,1
mov eax,4
int 0x80
ret
结果:"HBACTeyparleprelloe"
我当然希望这是一个打字错误,否则这将成为一个非常讨厌的练习!我将假设"HBACTeyparleprelleoe" .
它可以插入具有相同大小的string
你现在的代码似乎做正确,但为什么它是如此复杂?
如果当前索引(字符串中的偏移量)为0,则只执行movsb
。如果当前索引不是0,那么你需要跳过,你可以使用(浪费的)loop
/lodsb
指令来完成。有时人们想知道为什么rep lodsb
是允许的,这里他们有一点用例。虽然不是真的,因为实际的解决方案是替换:
mov esi,cad1 cld mov ecx,ebx cmp ebx,0 jne THEN1 je ELSE1 THEN1: lodsb loop THEN1 ELSE1: movsb
完全由:
lea esi, [cad1 + ebx]
movsb
或者:
movzx eax, byte [cad1 + ebx]
stosb
我不知道该怎么做才能使不同大小的字符串
下面我将给出三个解决方案,都经过测试。
解决方案1
因为精确地有5个输入字符串,32位x86架构有适当数量的寄存器来将单个指针保存在自己的寄存器中。这种方法给出了最快的代码,但前提是每个字符串的长度相差不太大。
S: db 43 dup 0
S1: db "Hello", 10
S2: db "Bye", 10
S3: db "AppleADayKeepsTheDoctorAway", 10
S4: db "Car", 10
S5: db "Tree", 10
...
Begin: mov ebx, S1 ; Addresses of the input strings
mov ecx, S2
mov edx, S3
mov esi, S4
mov edi, S5
mov ebp, S ; Address of the output string
.a: push ebp ; (1)
movzx eax, byte [ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .b ; no longer add to the output string
inc ebx ; Go to the next character in this string
mov [ebp], al ; Add character to the output string
inc ebp
.b: movzx eax, byte [ecx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .c ; no longer add to the output string
inc ecx ; Go to the next character in this string
mov [ebp], al ; Add character to the output string
inc ebp
.c: movzx eax, byte [edx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .d ; no longer add to the output string
inc edx ; Go to the next character in this string
mov [ebp], al ; Add character to the output string
inc ebp
.d: movzx eax, byte [esi] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .e ; no longer add to the output string
inc esi ; Go to the next character in this string
mov [ebp], al ; Add character to the output string
inc ebp
.e: movzx eax, byte [edi] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .f ; no longer add to the output string
inc edi ; Go to the next character in this string
mov [ebp], al ; Add character to the output string
inc ebp
.f: pop eax ; (1)
cmp eax, ebp ; Was anything added to the output string ?
jne .a ; Yes, then repeat
解决方案2
一个小编辑允许我们处理任意数量的输入字符串。这种方法比以前慢,但它需要填充字符串以使它们具有相同的长度(就像您在问题中遇到的那样)。
S: db 43 dup 0
S1: db "Hello", 22 dup 10, 10
S2: db "Bye", 24 dup 10, 10
S3: db "AppleADayKeepsTheDoctorAway", 10
S4: db "Car", 24 dup 10, 10
S5: db "Tree", 23 dup 10, 10
...
Begin: xor ebx, ebx ; Current offset in every string
mov ebp, S ; Address of the output string
.a: push ebp ; (1)
movzx eax, byte [S1 + ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .b ; no longer add to the output string
mov [ebp], al ; Add character to the output string
inc ebp
.b: movzx eax, byte [S2 + ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .c ; no longer add to the output string
mov [ebp], al ; Add character to the output string
inc ebp
.c: movzx eax, byte [S3 + ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .d ; no longer add to the output string
mov [ebp], al ; Add character to the output string
inc ebp
.d: movzx eax, byte [S4 + ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .e ; no longer add to the output string
mov [ebp], al ; Add character to the output string
inc ebp
.e: movzx eax, byte [S5 + ebx] ; Read a character from this string
cmp al, 10 ; If this string is exhausted, then
je .f ; no longer add to the output string
mov [ebp], al ; Add character to the output string
inc ebp
.f: inc ebx ; Go to next character in every string
pop eax ; (1)
cmp eax, ebp ; Was anything added to the output string ?
jne .a ; Yes, then repeat
3
解决方案这一次,我们创建了一个数组,其中包含指向各个字符串的指针。这些指针依次用于从关联的字符串中检索字符,当遇到字符串结束标记(10)时,只需从数组中删除相关指针。其他解决方案继续处理耗尽的字符串,但是这里耗尽的字符串从循环中消失。因为这个方法有更多的内务工作要做,所以它在非常常规的测试数据上运行得比较慢。然而,一旦你给它一个更现实的数据集,一个短字符串和长字符串,它会发光…对输入字符串的数量也没有限制,不需要填充,也不需要使用相同大小的字符串缓冲区(就像在你的程序中一样)。
P: dd S1, S2, S3, S4, S5, 0
S: db 43 dup 0
S1: db "Hello", 10
S2: db "Bye", 10
S3: db "AppleADayKeepsTheDoctorAway", 10
S4: db "Car", 10
S5: db "Tree", 10
...
Begin: mov ebp, S ; Address of the output string
jmp .e
.a: mov edi, ebx
.b: mov eax, [edi+4] ; Move all the stringpointers that follow
mov [edi], eax ; one position down in the array
add edi, 4
test eax, eax ; Until the zero-terminator got moved down
jnz .b
jmp .d ; Continue with the next stringpointer
.c: movzx eax, byte [esi] ; Read a character from the current string
cmp al, 10 ; If this string is exhausted, then
je .a ; go remove its pointer from the array
inc esi ; Go to the next character in the current string
mov [ebx], esi ; Update the current stringpointer
add ebx, 4 ; Go to the next stringpointer
mov [ebp], al ; Add character to the output string
inc ebp
.d: mov esi, [ebx] ; Get current stringpointer
test esi, esi ; Arrived at the end of the array if ESI is zero
jnz .c
.e: mov ebx, P ; Address of the array with stringpointers
mov esi, [ebx] ; Get current stringpointer
test esi, esi ; The array is empty if the 1st dword is zero
jnz .c