Bug in memcpy() for m68k

Yuichi Nakamura via Newlib <[email protected]> Sat, 28 Mar 2026 10:35:38 +0900
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Hi all,

I found the following issues in the m68k version of memcpy(). In 
particular, issue #1 is critical because it causes incorrect behavior on 
the 68000.

1. On CPUs that do not support misaligned access (MISALIGNED_OK=0), such 
as the 68000, memcpy() does not correctly copy regions larger than 64 KB 
when the destination is not long-word aligned.
2. The 68020 supports misaligned access, but this is not currently 
implemented.
3. The 68000 can access long-word data at even addresses, but alignment 
is checked as if the address must be a multiple of 4.
4. Because the loop count is checked using signed comparison, memcpy() 
fails for data sizes larger than 2 GB.

The following patch fixes these issues.

Best regards,
Yuichi Nakamura


diff --git a/newlib/libc/machine/m68k/memcpy.S 
b/newlib/libc/machine/m68k/memcpy.S
index 464da95ef..ecf1da611 100644
--- a/newlib/libc/machine/m68k/memcpy.S
+++ b/newlib/libc/machine/m68k/memcpy.S
@@ -15,7 +15,7 @@

  #include "m68kasm.h"

-#if defined (__mcoldfire__) || defined (__mc68030__) || defined 
(__mc68040__) || defined (__mc68060__)
+#if defined (__mcoldfire__) || defined (__mc68020__) || defined 
(__mc68030__) || defined (__mc68040__) || defined (__mc68060__)
  # define MISALIGNED_OK 1
  #else
  # define MISALIGNED_OK 0
@@ -49,10 +49,10 @@ SYM(memcpy):
  #if !MISALIGNED_OK
         /* Goto .Lresidue if either dest or src is not 4-byte aligned */
         move.l  a0,d0
-       and.l   #3,d0
+       and.l   #1,d0
         bne     .Lresidue
         move.l  a1,d0
-       and.l   #3,d0
+       and.l   #1,d0
         bne     .Lresidue
  #else /* MISALIGNED_OK */
         /* align dest */
@@ -95,7 +95,7 @@ SYM(memcpy):
  #else
         subq.l  #1,d0
  #endif
-       bpl     1b
+       bcc     1b
         bra     .Lresidue

  1:
@@ -104,9 +104,13 @@ SYM(memcpy):
  .Lresidue:
  #if !defined (__mcoldfire__)
         dbra    d1,1b           | loop until done
+#if !MISALIGNED_OK
+       sub.l   #0x10000,d1
+       bcc     1b
+#endif /* !MISALIGNED_OK */
  #else
         subq.l  #1,d1
-       bpl     1b
+       bcc     1b
  #endif
         move.l  4(sp),d0        | return value
         rts