如何在 Assembly 的特定位置将字符串插入其他字符串?
How to insert string into other string at certain position in Assembly?
对于我的作业,我正在尝试编写类似于 C++ insert 的 Insert 函数。
我的函数应该在某个位置将一个字符串插入到另一个字符串中。
输入:
destination : Be my friend today
source : good
position : 6
输出:
Be my good friend today
How should I make room in the middle of the string ?
到目前为止,这是我的代码。
Insert PROC PROC uses edi esi ebx ecx,
destination:DWORD ,
source:DWORD,
position:DWORD
mov esi,destination ;add esi address of str
add esi,position
add esi,4 ;lenght of source
mov edi,destination
add edi,position
;I don't know what should I do in here
;How should I make room in the middle of destination ?
;How should I insert at certain position + source length :-(
;Also, I shouldn't use loop and lea.
rep movsb
Insert ENDP
您应该为新的 "string" 保留内存,其长度为原始字符串的长度 + 要插入的字符串的长度。接下来从源字符串复制字符,直到指定的位置(根据字符宽度使用 LODSB 或 LODSW)。将 eds 指向新的输出字符串并将 edi 指向源数组。将 CX 设置为位置中的值。这会将字符从源内存复制到新的目标内存。然后将 edi 指向要插入的字符串,并将 cx 设置为要插入的字符串的长度。 运行 LODSW 最后一次将 edi 指向源字符串的位置,并将 cx 设置为源字符串的长度减去位置,最后一次 运行 lodsw。
到新字符串:
从原来的字符复制,然后复制新的字符,然后复制原来的尾部。
就地:
复制字符串的尾部,留出一个空隙来存放新的字符串。这就像 memmove
:因为复制的源和目标重叠,你应该从最后一个字符开始,所以你不会覆盖你还没有复制的字符。它也与 InsertionSort's copying to make room for a new element.
相同
您可能想要使用两个寄存器来跟踪源位置和目标位置。
我将避免提供任何代码,因为我无意为您编写作业,但我会尝试解释您将如何完成它。
我将做出以下假设:
1) destination
在其地址处有足够的内存来保存完整的字符串而不会覆盖任何其他变量。
2) 您实际上想要插入 "good "
(尾随 space),而不是 "good"
,因为如果您插入 "good"
,您将结束使用 "Be my goodfriend today"
(好友和朋友之间没有 space)。
3) 您实际上打算指定位置 5,而不是位置 6,因为 C++ insert
使用从零开始的位置(位置 0 是第一个字符,位置 1 是第二个,等等)。
您的第一步是复制字符串的右侧部分以腾出空间。您将从插入的起始位置复制字符,到起始位置加上要插入的字符串的大小,最后得到以下内容:
destination : Be my frienfriend today
这里有一个问题:您必须从 destination
的末尾向后 复制 以避免覆盖尚未复制的字符 - 如果您从偏移量 6 开始并将其复制到偏移量 11,您将覆盖需要先复制到偏移量 16 的偏移量 11 的值,而您最终会得到如下内容:
destination : Be my frienfrienfrienfri
通过向后复制,您可以避免这个问题。使用适当的 dec
或 sub
运算符的简单条件跳转将正常工作。
在为上面指定的源字符串腾出空间后,只需正确加载寄存器并使用 rep movsb
将源字符串复制到指定位置的目标位置,覆盖您已经拥有的字符即可已复制。
因此,destination
将包含 "Be my good friend today"
。
你的问题可以用两个函数来解决:第一个函数将字符串的字符从 SI 位置开始向右移动一个位置,第二个函数调用第一个函数 CX 次。这些函数是为插入新字符串腾出空间所必需的(我想您可以将它们合并为一个函数)。之后,很容易用源字符串覆盖目标字符串。我选择“$”来完成字符串,你可以用零或其他东西来改变它:
shift_right_once
;---------------------------------------------------
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, SI.
shift_right_once proc
mov al, [ si ] ;FIRST CHAR TO START PROCESS.
shifting:
cmp al, '$'
je end_shifting ;IF ( END OF STRING )
inc si
mov ah, [ si ]
mov [ si ], al
xchg al, ah
jmp shifting
end_shifting:
ret
shift_right_once endp
shift_right_cx
;---------------------------------------------------
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6
; CX = 3
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, CX.
shift_right_cx proc
push si
call shift_right_once ;CALL PREVIOUS FUNCTION.
pop si
loop shift_right_cx
ret
shift_right_cx endp
下一个小程序(用 EMU8086 制作)展示了如何使用它们:
.stack 100h
.data
destination db 'Be my friend today$$$$$$$$$$$$$$$$'
source db 'good $'
length dw 5 ;LENGTH OF "SOURCE".
position dw 6 ;POSITION TO INSERT.
.code
mov ax, @data
mov ds, ax
mov es, ax
;SHIFT CHARS TO THE RIGHT TO MAKE ROOM FOR NEW STRING.
mov cx, length ;HOW MANY CHARS TO PUSH.
mov si, offset destination
add si, position
call shift_right_cx
;OVERWRITE OLD CHARS WITH THE NEW ONES.
mov cx, length ;HOW MANY NEW CHARS.
mov di, si ;DI = DESTINATION.
mov si, offset source ;SI = SOURCE.
rep movsb ;DO { [DI]=[SI] } WHILE CX>0.
;WAIT FOR A KEY.
mov ah, 0
int 16h
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;---------------------------------------------------
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6 |
; CX = 3
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, CX.
shift_right_cx proc
push si
call shift_right_once ;SHIFT RIGHT CHARACTERS ONCE.
pop si
loop shift_right_cx
ret
shift_right_cx endp
;---------------------------------------------------
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6 |
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, SI.
shift_right_once proc
mov al, [ si ] ;FIRST CHAR TO START PROCESS.
shifting:
cmp al, '$'
je end_shifting ;IF ( END OF STRING )
inc si
mov ah, [ si ]
mov [ si ], al
xchg al, ah
jmp shifting
end_shifting:
ret
shift_right_once endp
希望对您有所帮助。
对于我的作业,我正在尝试编写类似于 C++ insert 的 Insert 函数。 我的函数应该在某个位置将一个字符串插入到另一个字符串中。
输入:
destination : Be my friend today
source : good
position : 6
输出:
Be my good friend today
How should I make room in the middle of the string ?
到目前为止,这是我的代码。
Insert PROC PROC uses edi esi ebx ecx,
destination:DWORD ,
source:DWORD,
position:DWORD
mov esi,destination ;add esi address of str
add esi,position
add esi,4 ;lenght of source
mov edi,destination
add edi,position
;I don't know what should I do in here
;How should I make room in the middle of destination ?
;How should I insert at certain position + source length :-(
;Also, I shouldn't use loop and lea.
rep movsb
Insert ENDP
您应该为新的 "string" 保留内存,其长度为原始字符串的长度 + 要插入的字符串的长度。接下来从源字符串复制字符,直到指定的位置(根据字符宽度使用 LODSB 或 LODSW)。将 eds 指向新的输出字符串并将 edi 指向源数组。将 CX 设置为位置中的值。这会将字符从源内存复制到新的目标内存。然后将 edi 指向要插入的字符串,并将 cx 设置为要插入的字符串的长度。 运行 LODSW 最后一次将 edi 指向源字符串的位置,并将 cx 设置为源字符串的长度减去位置,最后一次 运行 lodsw。
到新字符串:
从原来的字符复制,然后复制新的字符,然后复制原来的尾部。
就地:
复制字符串的尾部,留出一个空隙来存放新的字符串。这就像 memmove
:因为复制的源和目标重叠,你应该从最后一个字符开始,所以你不会覆盖你还没有复制的字符。它也与 InsertionSort's copying to make room for a new element.
您可能想要使用两个寄存器来跟踪源位置和目标位置。
我将避免提供任何代码,因为我无意为您编写作业,但我会尝试解释您将如何完成它。
我将做出以下假设:
1) destination
在其地址处有足够的内存来保存完整的字符串而不会覆盖任何其他变量。
2) 您实际上想要插入 "good "
(尾随 space),而不是 "good"
,因为如果您插入 "good"
,您将结束使用 "Be my goodfriend today"
(好友和朋友之间没有 space)。
3) 您实际上打算指定位置 5,而不是位置 6,因为 C++ insert
使用从零开始的位置(位置 0 是第一个字符,位置 1 是第二个,等等)。
您的第一步是复制字符串的右侧部分以腾出空间。您将从插入的起始位置复制字符,到起始位置加上要插入的字符串的大小,最后得到以下内容:
destination : Be my frienfriend today
这里有一个问题:您必须从 destination
的末尾向后 复制 以避免覆盖尚未复制的字符 - 如果您从偏移量 6 开始并将其复制到偏移量 11,您将覆盖需要先复制到偏移量 16 的偏移量 11 的值,而您最终会得到如下内容:
destination : Be my frienfrienfrienfri
通过向后复制,您可以避免这个问题。使用适当的 dec
或 sub
运算符的简单条件跳转将正常工作。
在为上面指定的源字符串腾出空间后,只需正确加载寄存器并使用 rep movsb
将源字符串复制到指定位置的目标位置,覆盖您已经拥有的字符即可已复制。
因此,destination
将包含 "Be my good friend today"
。
你的问题可以用两个函数来解决:第一个函数将字符串的字符从 SI 位置开始向右移动一个位置,第二个函数调用第一个函数 CX 次。这些函数是为插入新字符串腾出空间所必需的(我想您可以将它们合并为一个函数)。之后,很容易用源字符串覆盖目标字符串。我选择“$”来完成字符串,你可以用零或其他东西来改变它:
shift_right_once
;---------------------------------------------------
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, SI.
shift_right_once proc
mov al, [ si ] ;FIRST CHAR TO START PROCESS.
shifting:
cmp al, '$'
je end_shifting ;IF ( END OF STRING )
inc si
mov ah, [ si ]
mov [ si ], al
xchg al, ah
jmp shifting
end_shifting:
ret
shift_right_once endp
shift_right_cx
;---------------------------------------------------
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6
; CX = 3
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, CX.
shift_right_cx proc
push si
call shift_right_once ;CALL PREVIOUS FUNCTION.
pop si
loop shift_right_cx
ret
shift_right_cx endp
下一个小程序(用 EMU8086 制作)展示了如何使用它们:
.stack 100h
.data
destination db 'Be my friend today$$$$$$$$$$$$$$$$'
source db 'good $'
length dw 5 ;LENGTH OF "SOURCE".
position dw 6 ;POSITION TO INSERT.
.code
mov ax, @data
mov ds, ax
mov es, ax
;SHIFT CHARS TO THE RIGHT TO MAKE ROOM FOR NEW STRING.
mov cx, length ;HOW MANY CHARS TO PUSH.
mov si, offset destination
add si, position
call shift_right_cx
;OVERWRITE OLD CHARS WITH THE NEW ONES.
mov cx, length ;HOW MANY NEW CHARS.
mov di, si ;DI = DESTINATION.
mov si, offset source ;SI = SOURCE.
rep movsb ;DO { [DI]=[SI] } WHILE CX>0.
;WAIT FOR A KEY.
mov ah, 0
int 16h
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;---------------------------------------------------
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6 |
; CX = 3
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, CX.
shift_right_cx proc
push si
call shift_right_once ;SHIFT RIGHT CHARACTERS ONCE.
pop si
loop shift_right_cx
ret
shift_right_cx endp
;---------------------------------------------------
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS
;OF A STRING STARTING AT POSITION POINTED BY "SI".
;STRING MUST FINISH WITH "$".
;EXAMPLE: SI = 6 |
; INPUT = 'Be my friend today$$$$$$$$$$$$$$$$'
; OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$'
;MODIFIED REGISTERS : AX, SI.
shift_right_once proc
mov al, [ si ] ;FIRST CHAR TO START PROCESS.
shifting:
cmp al, '$'
je end_shifting ;IF ( END OF STRING )
inc si
mov ah, [ si ]
mov [ si ], al
xchg al, ah
jmp shifting
end_shifting:
ret
shift_right_once endp
希望对您有所帮助。