首页 > 解决方案 > 如何在汇编中实现 memmove,而不仅仅是 memcpy?

问题描述

我试图将 memmove 从 C 实现到 x86 程序集,所以我写道:

start:
    movb source(%eax), %cl
    movb %cl, destination(%eax)
    inc %eax
    cmp num, %eax
    jne start

end:

但这是错误的,为什么呢?根据:http ://www.cplusplus.com/reference/cstring/memmove/

将 num 个字节的值从 source 指向的位置复制到 destination 指向的内存块。复制就像使用了中间缓冲区一样进行允许目标和源重叠。

我的代码不支持。

如何在不使用堆栈的情况下解决此问题? 注意:我们可以假设在源目标进入内存之后,num(要复制的字节数)很远并且不能被错误触及。

标签: cassemblyx86attmemmove

解决方案


这里的问题是关于潜在的重叠情况destination - source < size(即两者都source指向destination同一个数据块)。发生这种情况时,您将处于以下情况:

AAAAAAAAAAAAAABBBBBBBBBBBBBB_______________________
^             ^             ^             ^
source        destination   source        destination
                             + num        + num

如果您从 开始复制source,您将覆盖您尝试复制的部分内容(在此示例中,您将B用s 覆盖As),丢失原始值,最终结果如下:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_________
^             ^             ^             ^
source        destination   source        destination
                             + num        + num

在现实中你想要这个:

AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBB_________
^             ^             ^             ^
source        destination   source        destination
                             + num        + num

destination - source < num您可以通过检查 when并在这种情况下反向复制(以 开头)来解决此问题eax = num

相应的程序集将是这样的:

    mov  $destination, %eax
    sub  $source, %eax             # dst-src distance in bytes
    cmp  num, %eax
    jb  backwards                  # if (dst-src < copy_size) goto backwards

forward:
    mov  $0, %eax
forward_loop:
    movb source(%eax), %cl
    movb %cl, destination(%eax)
    inc %eax
    cmp num, %eax
    jne forward_loop
    jmp end

backwards:
    movl  num, %eax        # start from i=length
backwards_loop:
    movb  source-1(%eax), %cl
    movb  %cl, destination-1(%eax)
    dec   %eax
    jnz   backwards_loop

end:

推荐阅读