From a7cb446de827013fc5ee082b9c60e19baf9ffc5d Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Fri, 28 Apr 2023 01:52:18 -0400
Subject: [PATCH 01/15] Add more C lib methods

---
 base/libc.jl         | 36 ++++++++++++++++++++++++++++++++++++
 doc/src/base/libc.md |  4 ++++
 2 files changed, 40 insertions(+)

diff --git a/base/libc.jl b/base/libc.jl
index 82286fbf01af6..b330684246f64 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -371,6 +371,42 @@ Call `calloc` from the C standard library.
 """
 calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
 
+"""
+    memcpy(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
+
+Call `memcpy` from the C standard library.
+"""
+function memcpy(dst::Ptr, src::Ptr, n::Integer)
+    ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
+end
+
+"""
+    memmove(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
+
+Call `memmove` from the C standard library.
+"""
+function memmove(dst::Ptr, src::Ptr, n::Integer)
+    ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
+end
+
+"""
+    memset(dst::Ptr, val, n::Integer) -> Ptr{Cvoid}
+
+Call `memset` from the C standard library.
+"""
+function memset(p::Ptr, val, n::Integer)
+    ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), p, val, n)
+end
+
+"""
+    memcmp(a::Ptr, b::Ptr, n::Integer) -> Int
+
+Call `memcmp` from the C standard library.
+"""
+function memcmp(a::Ptr, b::Ptr, n::Integer)
+    ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, n % Csize_t) % Int
+end
+
 free(p::Cstring) = free(convert(Ptr{UInt8}, p))
 free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
 
diff --git a/doc/src/base/libc.md b/doc/src/base/libc.md
index 0af1b74a79a71..08d2670123234 100644
--- a/doc/src/base/libc.md
+++ b/doc/src/base/libc.md
@@ -4,6 +4,10 @@
 Base.Libc.malloc
 Base.Libc.calloc
 Base.Libc.realloc
+Base.Libc.memcpy
+Base.Libc.memmove
+Base.Libc.memset
+Base.Libc.memcmp
 Base.Libc.free
 Base.Libc.errno
 Base.Libc.strerror

From 4940f60e45303803cc0a656d089186362cd711d8 Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Fri, 28 Apr 2023 21:52:16 -0400
Subject: [PATCH 02/15] Replace ccall's with Libc methods

Some ccalls remain in order to accomodate bootstraps still
---
 base/libc.jl                                  |  5 +++--
 base/mpfr.jl                                  |  2 +-
 base/reinterpretarray.jl                      | 10 ++++------
 base/ryu/Ryu.jl                               |  1 +
 base/ryu/shortest.jl                          | 20 +++++++++----------
 base/ryu/utils.jl                             |  3 ---
 base/util.jl                                  |  2 +-
 .../InteractiveUtils/src/InteractiveUtils.jl  |  2 +-
 stdlib/InteractiveUtils/src/clipboard.jl      |  2 +-
 stdlib/Random/src/DSFMT.jl                    |  3 +--
 stdlib/Random/src/Random.jl                   |  2 +-
 stdlib/Random/src/XoshiroSimd.jl              |  4 ++--
 12 files changed, 26 insertions(+), 30 deletions(-)

diff --git a/base/libc.jl b/base/libc.jl
index b330684246f64..7db2336863067 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -8,8 +8,9 @@ Interface to libc, the C standard library.
 import Base: transcode, windowserror, show
 import Core.Intrinsics: bitcast
 
-export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, calloc, realloc,
-    errno, strerror, flush_cstdio, systemsleep, time, transcode
+export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, memcpy,
+    memmove, memset, calloc, realloc, errno, strerror, flush_cstdio, systemsleep, time,
+    transcode
 if Sys.iswindows()
     export GetLastError, FormatMessage
 end
diff --git a/base/mpfr.jl b/base/mpfr.jl
index ff85fc6155df4..a83b2456bc7f3 100644
--- a/base/mpfr.jl
+++ b/base/mpfr.jl
@@ -1140,7 +1140,7 @@ function decompose(x::BigFloat)::Tuple{BigInt, Int, Int}
     s.size = cld(x.prec, 8*sizeof(Limb)) # limbs
     b = s.size * sizeof(Limb)            # bytes
     ccall((:__gmpz_realloc2, libgmp), Cvoid, (Ref{BigInt}, Culong), s, 8b) # bits
-    ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), s.d, x.d, b) # bytes
+    mempcy(s.d, x.d, b)
     s, x.exp - 8b, x.sign
 end
 
diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl
index 2fc246f86fa96..830bac90d86e9 100644
--- a/base/reinterpretarray.jl
+++ b/base/reinterpretarray.jl
@@ -387,8 +387,6 @@ end
     end
 end
 
-@inline _memcpy!(dst, src, n) = ccall(:memcpy, Cvoid, (Ptr{UInt8}, Ptr{UInt8}, Csize_t), dst, src, n)
-
 @inline @propagate_inbounds function _getindex_ra(a::NonReshapedReinterpretArray{T,N,S}, i1::Int, tailinds::TT) where {T,N,S,TT}
     # Make sure to match the scalar reinterpret if that is applicable
     if sizeof(T) == sizeof(S) && (fieldcount(T) + fieldcount(S)) == 0
@@ -434,7 +432,7 @@ end
                 while nbytes_copied < sizeof(T)
                     s[] = a.parent[ind_start + i, tailinds...]
                     nb = min(sizeof(S) - sidx, sizeof(T)-nbytes_copied)
-                    _memcpy!(tptr + nbytes_copied, sptr + sidx, nb)
+                    memcpy(tptr + nbytes_copied, sptr + sidx, nb)
                     nbytes_copied += nb
                     sidx = 0
                     i += 1
@@ -574,7 +572,7 @@ end
                 if sidx != 0
                     s[] = a.parent[ind_start + i, tailinds...]
                     nb = min((sizeof(S) - sidx) % UInt, sizeof(T) % UInt)
-                    _memcpy!(sptr + sidx, tptr, nb)
+                    memcpy(sptr + sidx, tptr, nb)
                     nbytes_copied += nb
                     a.parent[ind_start + i, tailinds...] = s[]
                     i += 1
@@ -583,7 +581,7 @@ end
                 # Deal with the main body of elements
                 while nbytes_copied < sizeof(T) && (sizeof(T) - nbytes_copied) > sizeof(S)
                     nb = min(sizeof(S), sizeof(T) - nbytes_copied)
-                    _memcpy!(sptr, tptr + nbytes_copied, nb)
+                    memcpy(sptr, tptr + nbytes_copied, nb)
                     nbytes_copied += nb
                     a.parent[ind_start + i, tailinds...] = s[]
                     i += 1
@@ -592,7 +590,7 @@ end
                 if nbytes_copied < sizeof(T)
                     s[] = a.parent[ind_start + i, tailinds...]
                     nb = min(sizeof(S), sizeof(T) - nbytes_copied)
-                    _memcpy!(sptr, tptr + nbytes_copied, nb)
+                    memcpy(sptr, tptr + nbytes_copied, nb)
                     a.parent[ind_start + i, tailinds...] = s[]
                 end
             end
diff --git a/base/ryu/Ryu.jl b/base/ryu/Ryu.jl
index 81d1c41f4c19f..9b236caeb6ff1 100644
--- a/base/ryu/Ryu.jl
+++ b/base/ryu/Ryu.jl
@@ -1,5 +1,6 @@
 module Ryu
 
+using .Base.Libc
 import .Base: significand_bits, significand_mask, exponent_bits, exponent_mask, exponent_bias, exponent_max, uinttype
 
 include("utils.jl")
diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl
index f95c09d235e6d..bd9bfb7a538ec 100644
--- a/base/ryu/shortest.jl
+++ b/base/ryu/shortest.jl
@@ -363,10 +363,10 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
         c1 = (c ÷ 100) << 1
         d0 = (d % 100) << 1
         d1 = (d ÷ 100) << 1
-        memcpy(ptr, pos + olength - 2, ptr2, c0 + 1, 2)
-        memcpy(ptr, pos + olength - 4, ptr2, c1 + 1, 2)
-        memcpy(ptr, pos + olength - 6, ptr2, d0 + 1, 2)
-        memcpy(ptr, pos + olength - 8, ptr2, d1 + 1, 2)
+        memcpy(ptr + pos + olength - 3, ptr2 + c0, 2)
+        memcpy(ptr + pos + olength - 5, ptr2 + c1, 2)
+        memcpy(ptr + pos + olength - 7, ptr2 + d0, 2)
+        memcpy(ptr + pos + olength - 9, ptr2 + d1, 2)
         i += 8
     end
     output2 = output % UInt32
@@ -375,14 +375,14 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
         output2 = div(output2, UInt32(10000))
         c0 = (c % 100) << 1
         c1 = (c ÷ 100) << 1
-        memcpy(ptr, pos + olength - i - 2, ptr2, c0 + 1, 2)
-        memcpy(ptr, pos + olength - i - 4, ptr2, c1 + 1, 2)
+        memcpy(ptr + pos + olength - i - 1, ptr2 + c0, 2)
+        memcpy(ptr + pos + olength - i - 3, ptr2 + c1, 2)
         i += 4
     end
     if output2 >= 100
         c = (output2 % UInt32(100)) << 1
         output2 = div(output2, UInt32(100))
-        memcpy(ptr, pos + olength - i - 2, ptr2, c + 1, 2)
+        memcpy(ptr + pos + olength - i - 3, ptr2 + c, 2)
         i += 2
     end
     if output2 >= 10
@@ -425,7 +425,7 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
             end
         else
             pointoff = olength - abs(nexp)
-            memmove(ptr, pos + pointoff + 1, ptr, pos + pointoff, olength - pointoff + 1)
+            memmove(ptr + pos + pointoff, ptr + pos + pointoff - 1, olength - pointoff + 1)
             buf[pos + pointoff] = decchar
             pos += olength + 1
             precision -= olength
@@ -470,11 +470,11 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
 
         if exp2 >= 100
             c = exp2 % 10
-            memcpy(ptr, pos, ptr2, 2 * div(exp2, 10) + 1, 2)
+            memcpy(ptr + pos - 1, ptr2 + 2 * div(exp2, 10), 2)
             buf[pos + 2] = UInt8('0') + (c % UInt8)
             pos += 3
         elseif exp2 >= 10
-            memcpy(ptr, pos, ptr2, 2 * exp2 + 1, 2)
+            memcpy(ptr + pos - 1, ptr2 + 2 * exp2, 2)
             pos += 2
         else
             if padexp
diff --git a/base/ryu/utils.jl b/base/ryu/utils.jl
index 4fe0b7d397d07..f5a88c057e2b3 100644
--- a/base/ryu/utils.jl
+++ b/base/ryu/utils.jl
@@ -1,9 +1,6 @@
 const MANTISSA_MASK = Base.significand_mask(Float64)
 const EXP_MASK = Base.exponent_mask(Float64) >> Base.significand_bits(Float64)
 
-memcpy(d, doff, s, soff, n) = (ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), d + doff - 1, s + soff - 1, n); nothing)
-memmove(d, doff, s, soff, n) = (ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), d + doff - 1, s + soff - 1, n); nothing)
-
 # Note: these are smaller than the values given in Figure 4 from the paper
 # see https://github.com/ulfjack/ryu/issues/119
 pow5_bitcount(::Type{Float16}) = 30
diff --git a/base/util.jl b/base/util.jl
index 6f424f80d13b6..c7a036a6dff69 100644
--- a/base/util.jl
+++ b/base/util.jl
@@ -268,7 +268,7 @@ will always be called.
 function securezero! end
 @noinline securezero!(a::AbstractArray{<:Number}) = fill!(a, 0)
 @noinline unsafe_securezero!(p::Ptr{T}, len::Integer=1) where {T} =
-    ccall(:memset, Ptr{T}, (Ptr{T}, Cint, Csize_t), p, 0, len*sizeof(T))
+    memset(p, 0, len*sizeof(T))
 unsafe_securezero!(p::Ptr{Cvoid}, len::Integer=1) = Ptr{Cvoid}(unsafe_securezero!(Ptr{UInt8}(p), len))
 
 """
diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl
index 48fc2b7dafe8f..5fbe19ac4efce 100644
--- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl
+++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl
@@ -12,7 +12,7 @@ import Base.Docs.apropos
 
 using Base: unwrap_unionall, rewrap_unionall, isdeprecated, Bottom, show_unquoted, summarysize,
     signature_type, format_bytes
-
+using Base.Libc
 using Markdown
 
 include("editless.jl")
diff --git a/stdlib/InteractiveUtils/src/clipboard.jl b/stdlib/InteractiveUtils/src/clipboard.jl
index a4a5118acf8d7..2a0a707026671 100644
--- a/stdlib/InteractiveUtils/src/clipboard.jl
+++ b/stdlib/InteractiveUtils/src/clipboard.jl
@@ -100,7 +100,7 @@ elseif Sys.iswindows()
         pdata == C_NULL && return cleanup(:GlobalAlloc)
         plock = ccall((:GlobalLock, "kernel32"), stdcall, Ptr{UInt16}, (Ptr{UInt16},), pdata)
         plock == C_NULL && return cleanup(:GlobalLock)
-        ccall(:memcpy, Ptr{UInt16}, (Ptr{UInt16}, Ptr{UInt16}, Csize_t), plock, x_u16, sizeof(x_u16))
+        memcpy(plock, x_u16, sizeof(x_u16))
         unlock = ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{UInt16},), pdata)
         (unlock == 0 && Libc.GetLastError() == 0) || return cleanup(:GlobalUnlock) # this should never fail
         pset = ccall((:SetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint, Ptr{UInt16}), 13, pdata) # CF_UNICODETEXT
diff --git a/stdlib/Random/src/DSFMT.jl b/stdlib/Random/src/DSFMT.jl
index f72a9dd5e9a0a..d3d7ce4a56a5d 100644
--- a/stdlib/Random/src/DSFMT.jl
+++ b/stdlib/Random/src/DSFMT.jl
@@ -194,8 +194,7 @@ function dsfmt_jump(s::DSFMT_state, jp::GF2X)
     work = zeros(Int32, JN32)
     rwork = reinterpret(UInt64, work)
     dsfmt = Vector{UInt64}(undef, nval >> 1)
-    ccall(:memcpy, Ptr{Cvoid}, (Ptr{UInt64}, Ptr{Int32}, Csize_t),
-          dsfmt, val, (nval - 1) * sizeof(Int32))
+    memcpy(dsfmt, val, (nval - 1) * sizeof(Int32))
     dsfmt[end] = UInt64(N*2)
 
     for i in 0:degree(jp)
diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl
index 8da2dd6f3e9c7..7c13c63e208e1 100644
--- a/stdlib/Random/src/Random.jl
+++ b/stdlib/Random/src/Random.jl
@@ -16,7 +16,7 @@ using Base.GMP: Limb
 import SHA
 
 using Base: BitInteger, BitInteger_types, BitUnsigned, require_one_based_indexing
-
+using Base.Libc
 import Base: copymutable, copy, copy!, ==, hash, convert,
              rand, randn, show
 
diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index 9fb03f9572688..7f8816f30f105 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -180,7 +180,7 @@ end
         s3 = _rotl45(s3)
         ref = Ref(f(res, T))
         # TODO: This may make the random-stream dependent on system endianness
-        ccall(:memcpy, Ptr{Cvoid}, (Ptr{UInt8}, Ptr{UInt64}, Csize_t), dst+i, ref, len-i)
+        memcpy(dst+i, ref, len-i)
     end
     if rng isa TaskLocalRNG
         task.rngState0, task.rngState1, task.rngState2, task.rngState3 = s0, s1, s2, s3
@@ -222,7 +222,7 @@ end
         res = _plus(_rotl23(_plus(s0,s3)),s0)
         resLoc = _and(res, 0x0101010101010101)
         ref = Ref(resLoc)
-        ccall(:memcpy, Ptr{Cvoid}, (Ptr{UInt8}, Ptr{UInt64}, Csize_t), dst+i, ref, len-i)
+        memcpy(dst+i, ref, len-i)
         t = _shl17(s1)
         s2 = _xor(s2, s0)
         s3 = _xor(s3, s1)

From 015e7444459aefe86b4fe2e0afea0bd854e9dbed Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Sat, 29 Apr 2023 17:22:55 -0400
Subject: [PATCH 03/15] Add import statement and compat notes

---
 base/libc.jl                     | 16 ++++++++++++++++
 base/mpfr.jl                     |  4 +++-
 stdlib/Random/src/XoshiroSimd.jl |  3 ++-
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/base/libc.jl b/base/libc.jl
index 7db2336863067..8897d1b553413 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -376,6 +376,10 @@ calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize
     memcpy(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
 
 Call `memcpy` from the C standard library.
+
+!!! compat "Julia 1.9"
+    Support for `memcpy` as a tuple requires at least Julia 1.9.
+
 """
 function memcpy(dst::Ptr, src::Ptr, n::Integer)
     ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
@@ -385,6 +389,10 @@ end
     memmove(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
 
 Call `memmove` from the C standard library.
+
+!!! compat "Julia 1.9"
+    Support for `memmove` as a tuple requires at least Julia 1.9.
+
 """
 function memmove(dst::Ptr, src::Ptr, n::Integer)
     ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
@@ -394,6 +402,10 @@ end
     memset(dst::Ptr, val, n::Integer) -> Ptr{Cvoid}
 
 Call `memset` from the C standard library.
+
+!!! compat "Julia 1.9"
+    Support for `memset` as a tuple requires at least Julia 1.9.
+
 """
 function memset(p::Ptr, val, n::Integer)
     ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), p, val, n)
@@ -403,6 +415,10 @@ end
     memcmp(a::Ptr, b::Ptr, n::Integer) -> Int
 
 Call `memcmp` from the C standard library.
+
+!!! compat "Julia 1.9"
+    Support for `memcmp` as a tuple requires at least Julia 1.9.
+
 """
 function memcmp(a::Ptr, b::Ptr, n::Integer)
     ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, n % Csize_t) % Int
diff --git a/base/mpfr.jl b/base/mpfr.jl
index a83b2456bc7f3..01cd6a2342fdf 100644
--- a/base/mpfr.jl
+++ b/base/mpfr.jl
@@ -19,6 +19,8 @@ import
         isone, big, _string_n, decompose, minmax,
         sinpi, cospi, sincospi, tanpi, sind, cosd, tand, asind, acosd, atand
 
+
+import .Base.Libc
 import ..Rounding: rounding_raw, setrounding_raw
 
 import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb, libgmp
@@ -1140,7 +1142,7 @@ function decompose(x::BigFloat)::Tuple{BigInt, Int, Int}
     s.size = cld(x.prec, 8*sizeof(Limb)) # limbs
     b = s.size * sizeof(Limb)            # bytes
     ccall((:__gmpz_realloc2, libgmp), Cvoid, (Ref{BigInt}, Culong), s, 8b) # bits
-    mempcy(s.d, x.d, b)
+    memcpy(s.d, x.d, b)
     s, x.exp - 8b, x.sign
 end
 
diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index 7f8816f30f105..e3b44311ba717 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -5,6 +5,7 @@ module XoshiroSimd
 import ..Random: TaskLocalRNG, rand, rand!, Xoshiro, CloseOpen01, UnsafeView,
                  SamplerType, SamplerTrivial
 using Base: BitInteger_types
+using Base.Libc
 using Core.Intrinsics: llvmcall
 
 # Vector-width. Influences random stream.
@@ -180,7 +181,7 @@ end
         s3 = _rotl45(s3)
         ref = Ref(f(res, T))
         # TODO: This may make the random-stream dependent on system endianness
-        memcpy(dst+i, ref, len-i)
+        memcpy(dst+i, pointer_from_objref(ref), len-i)
     end
     if rng isa TaskLocalRNG
         task.rngState0, task.rngState1, task.rngState2, task.rngState3 = s0, s1, s2, s3

From e54bbc41aabc705802af3f920ea4b881326b3ac9 Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Sun, 30 Apr 2023 12:27:59 -0400
Subject: [PATCH 04/15] Fix comapt notes

---
 base/libc.jl         | 16 ++++++++--------
 base/ryu/shortest.jl |  4 ++--
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/base/libc.jl b/base/libc.jl
index 8897d1b553413..90c5b55127230 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -377,8 +377,8 @@ calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize
 
 Call `memcpy` from the C standard library.
 
-!!! compat "Julia 1.9"
-    Support for `memcpy` as a tuple requires at least Julia 1.9.
+!!! compat "Julia 1.10"
+    Support for `memcpy` requires at least Julia 1.10.
 
 """
 function memcpy(dst::Ptr, src::Ptr, n::Integer)
@@ -390,8 +390,8 @@ end
 
 Call `memmove` from the C standard library.
 
-!!! compat "Julia 1.9"
-    Support for `memmove` as a tuple requires at least Julia 1.9.
+!!! compat "Julia 1.10"
+    Support for `memmove` requires at least Julia 1.10.
 
 """
 function memmove(dst::Ptr, src::Ptr, n::Integer)
@@ -403,8 +403,8 @@ end
 
 Call `memset` from the C standard library.
 
-!!! compat "Julia 1.9"
-    Support for `memset` as a tuple requires at least Julia 1.9.
+!!! compat "Julia 1.10"
+    Support for `memset` requires at least Julia 1.10.
 
 """
 function memset(p::Ptr, val, n::Integer)
@@ -416,8 +416,8 @@ end
 
 Call `memcmp` from the C standard library.
 
-!!! compat "Julia 1.9"
-    Support for `memcmp` as a tuple requires at least Julia 1.9.
+!!! compat "Julia 1.10"
+    Support for `memcmp` requires at least Julia 1.9.
 
 """
 function memcmp(a::Ptr, b::Ptr, n::Integer)
diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl
index bd9bfb7a538ec..9f46b0e9380b8 100644
--- a/base/ryu/shortest.jl
+++ b/base/ryu/shortest.jl
@@ -375,8 +375,8 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
         output2 = div(output2, UInt32(10000))
         c0 = (c % 100) << 1
         c1 = (c ÷ 100) << 1
-        memcpy(ptr + pos + olength - i - 1, ptr2 + c0, 2)
-        memcpy(ptr + pos + olength - i - 3, ptr2 + c1, 2)
+        memcpy(ptr + pos + olength - i - 3, ptr2 + c0, 2)
+        memcpy(ptr + pos + olength - i - 4, ptr2 + c1, 2)
         i += 4
     end
     if output2 >= 100

From 1cf6d5ccfc0c8c2a39161fcf62c510bdb1906576 Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Mon, 8 May 2023 15:55:41 -0400
Subject: [PATCH 05/15] Fix imports and general adoption of C fxns

---
 base/Base.jl                     | 2 +-
 base/mpfr.jl                     | 2 +-
 base/ryu/shortest.jl             | 2 +-
 stdlib/Random/src/XoshiroSimd.jl | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/base/Base.jl b/base/Base.jl
index 06df2edb276fd..5dd1227b6c534 100644
--- a/base/Base.jl
+++ b/base/Base.jl
@@ -316,7 +316,7 @@ include("version.jl")
 # system & environment
 include("sysinfo.jl")
 include("libc.jl")
-using .Libc: getpid, gethostname, time
+using .Libc: getpid, gethostname, time, memcpy, memset
 
 # These used to be in build_h.jl and are retained for backwards compatibility.
 # NOTE: keep in sync with `libblastrampoline_jll.libblastrampoline`.
diff --git a/base/mpfr.jl b/base/mpfr.jl
index 01cd6a2342fdf..2e03018f7669f 100644
--- a/base/mpfr.jl
+++ b/base/mpfr.jl
@@ -20,7 +20,7 @@ import
         sinpi, cospi, sincospi, tanpi, sind, cosd, tand, asind, acosd, atand
 
 
-import .Base.Libc
+using .Base.Libc
 import ..Rounding: rounding_raw, setrounding_raw
 
 import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb, libgmp
diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl
index 9f46b0e9380b8..aaa62ba33c703 100644
--- a/base/ryu/shortest.jl
+++ b/base/ryu/shortest.jl
@@ -376,7 +376,7 @@ function writeshortest(buf::Vector{UInt8}, pos, x::T,
         c0 = (c % 100) << 1
         c1 = (c ÷ 100) << 1
         memcpy(ptr + pos + olength - i - 3, ptr2 + c0, 2)
-        memcpy(ptr + pos + olength - i - 4, ptr2 + c1, 2)
+        memcpy(ptr + pos + olength - i - 5, ptr2 + c1, 2)
         i += 4
     end
     if output2 >= 100
diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index e3b44311ba717..fcd13d0d23671 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -223,7 +223,7 @@ end
         res = _plus(_rotl23(_plus(s0,s3)),s0)
         resLoc = _and(res, 0x0101010101010101)
         ref = Ref(resLoc)
-        memcpy(dst+i, ref, len-i)
+        memcpy(dst+i, pointer_from_objref(ref), len-i)
         t = _shl17(s1)
         s2 = _xor(s2, s0)
         s3 = _xor(s3, s1)

From 1b0828d0a2c9c09aff882ef04c6ee64fe50bbb81 Mon Sep 17 00:00:00 2001
From: Zachary P Christensen <zchristensen7@gmail.com>
Date: Tue, 9 May 2023 03:56:25 -0400
Subject: [PATCH 06/15] Update stdlib/Random/src/XoshiroSimd.jl

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
---
 stdlib/Random/src/XoshiroSimd.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index fcd13d0d23671..6eebd745ef867 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -181,7 +181,7 @@ end
         s3 = _rotl45(s3)
         ref = Ref(f(res, T))
         # TODO: This may make the random-stream dependent on system endianness
-        memcpy(dst+i, pointer_from_objref(ref), len-i)
+        GC.@preserve ref memcpy(dst+i, pointer_from_objref(ref), len-i)
     end
     if rng isa TaskLocalRNG
         task.rngState0, task.rngState1, task.rngState2, task.rngState3 = s0, s1, s2, s3

From 9c83ccda1a39ce2dcbfd351bc5c2e9902de816e6 Mon Sep 17 00:00:00 2001
From: Zachary P Christensen <zchristensen7@gmail.com>
Date: Tue, 9 May 2023 03:56:31 -0400
Subject: [PATCH 07/15] Update stdlib/Random/src/XoshiroSimd.jl

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
---
 stdlib/Random/src/XoshiroSimd.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index 6eebd745ef867..6cc587773ee9f 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -223,7 +223,7 @@ end
         res = _plus(_rotl23(_plus(s0,s3)),s0)
         resLoc = _and(res, 0x0101010101010101)
         ref = Ref(resLoc)
-        memcpy(dst+i, pointer_from_objref(ref), len-i)
+        GC.@preserve ref memcpy(dst+i, pointer_from_objref(ref), len-i)
         t = _shl17(s1)
         s2 = _xor(s2, s0)
         s3 = _xor(s3, s1)

From 74a7c008a3aec890f2c44784086a431727e6343d Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Tue, 9 May 2023 04:00:59 -0400
Subject: [PATCH 08/15] Add news

---
 NEWS.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/NEWS.md b/NEWS.md
index 5a518104d3770..404b2b11687af 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -44,6 +44,7 @@ New library functions
 * `tanpi` is now defined. It computes tan(πx) more accurately than `tan(pi*x)` ([#48575]).
 * `fourthroot(x)` is now defined in `Base.Math` and can be used to compute the fourth root of `x`.
    It can also be accessed using the unicode character `∜`, which can be typed by `\fourthroot<tab>` ([#48899]).
+* `Libc.memmove`, `Libc.memset`, and `Libc.memcpy` are now defined, whose functionality matches that of their respective C calls.
 
 New library features
 --------------------

From 08827ec872c3dec1bf9c1f9bf27675d67a4f55ac Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Thu, 11 May 2023 10:40:37 -0400
Subject: [PATCH 09/15] Make C-memory calls available from bootstrapping

The Libc module contains some code that we might not care to have as
part of bootstrapping. However, the C-memory methods are directly called
throughout bootstrapping so these are now defined in a seperate
"cmem.jl" file that is defined in Base then imported into `Libc` for the
public interface.
---
 base/Base.jl              |   3 +-
 base/array.jl             |  11 ++---
 base/cmem.jl              | 101 ++++++++++++++++++++++++++++++++++++++
 base/compiler/compiler.jl |   1 +
 base/iddict.jl            |   5 +-
 base/libc.jl              |  93 +----------------------------------
 base/refpointer.jl        |  11 -----
 base/strings/string.jl    |   2 +-
 base/strings/substring.jl |   2 +-
 9 files changed, 116 insertions(+), 113 deletions(-)
 create mode 100644 base/cmem.jl

diff --git a/base/Base.jl b/base/Base.jl
index 5dd1227b6c534..65abe47f33d2d 100644
--- a/base/Base.jl
+++ b/base/Base.jl
@@ -163,6 +163,7 @@ include("int.jl")
 include("operators.jl")
 include("pointer.jl")
 include("refvalue.jl")
+include("cmem.jl")
 include("refpointer.jl")
 
 # now replace the Pair constructor (relevant for NamedTuples) with one that calls our Base.convert
@@ -316,7 +317,7 @@ include("version.jl")
 # system & environment
 include("sysinfo.jl")
 include("libc.jl")
-using .Libc: getpid, gethostname, time, memcpy, memset
+using .Libc: getpid, gethostname, time, memcpy, memset, memmove, memcmp
 
 # These used to be in build_h.jl and are retained for backwards compatibility.
 # NOTE: keep in sync with `libblastrampoline_jll.libblastrampoline`.
diff --git a/base/array.jl b/base/array.jl
index 68e3e38992731..b075fc8536ac9 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -280,8 +280,7 @@ segfault your program, in the same manner as C.
 function unsafe_copyto!(dest::Ptr{T}, src::Ptr{T}, n) where T
     # Do not use this to copy data between pointer arrays.
     # It can't be made safe no matter how carefully you checked.
-    ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
-          dest, src, n * aligned_sizeof(T))
+    memmove(dest, src, n * aligned_sizeof(T))
     return dest
 end
 
@@ -328,13 +327,11 @@ function unsafe_copyto!(dest::Array{T}, doffs, src::Array{T}, soffs, n) where T
         ccall(:jl_array_ptr_copy, Cvoid, (Any, Ptr{Cvoid}, Any, Ptr{Cvoid}, Int),
               dest, destp, src, srcp, n)
     elseif isbitstype(T)
-        ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
-              destp, srcp, n * aligned_sizeof(T))
+        memmove(destp, srcp, n * aligned_sizeof(T))
     elseif isbitsunion(T)
-        ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
-              destp, srcp, n * aligned_sizeof(T))
+        memmove(destp, srcp, n * aligned_sizeof(T))
         # copy selector bytes
-        ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
+        memmove(
               ccall(:jl_array_typetagdata, Ptr{UInt8}, (Any,), dest) + doffs - 1,
               ccall(:jl_array_typetagdata, Ptr{UInt8}, (Any,), src) + soffs - 1,
               n)
diff --git a/base/cmem.jl b/base/cmem.jl
new file mode 100644
index 0000000000000..04b8b1b38c0fa
--- /dev/null
+++ b/base/cmem.jl
@@ -0,0 +1,101 @@
+# This file is a part of Julia. License is MIT: https://julialang.org/license
+
+# C NUL-terminated string pointers; these can be used in ccall
+# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
+# a check for embedded NUL chars in the string (to avoid silent truncation).
+if Int === Int64
+    primitive type Cstring  64 end
+    primitive type Cwstring 64 end
+else
+    primitive type Cstring  32 end
+    primitive type Cwstring 32 end
+end
+
+"""
+    free(addr::Ptr)
+
+Call `free` from the C standard library. Only use this on memory obtained from [`malloc`](@ref), not
+on pointers retrieved from other C libraries. [`Ptr`](@ref) objects obtained from C libraries should
+be freed by the free functions defined in that library, to avoid assertion failures if
+multiple `libc` libraries exist on the system.
+"""
+free(p::Ptr) = ccall(:free, Cvoid, (Ptr{Cvoid},), p)
+free(p::Cstring) = free(convert(Ptr{UInt8}, p))
+free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
+
+"""
+    malloc(size::Integer) -> Ptr{Cvoid}
+
+Call `malloc` from the C standard library.
+"""
+malloc(size::Integer) = ccall(:malloc, Ptr{Cvoid}, (Csize_t,), size)
+
+"""
+    realloc(addr::Ptr, size::Integer) -> Ptr{Cvoid}
+
+Call `realloc` from the C standard library.
+
+See warning in the documentation for [`free`](@ref) regarding only using this on memory originally
+obtained from [`malloc`](@ref).
+"""
+realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), p, size)
+
+"""
+    calloc(num::Integer, size::Integer) -> Ptr{Cvoid}
+
+Call `calloc` from the C standard library.
+"""
+calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
+
+"""
+    memcpy(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
+
+Call `memcpy` from the C standard library.
+
+!!! compat "Julia 1.10"
+    Support for `memcpy` requires at least Julia 1.10.
+
+"""
+function memcpy(dst::Ptr, src::Ptr, n::Integer)
+    ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
+end
+
+"""
+    memmove(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
+
+Call `memmove` from the C standard library.
+
+!!! compat "Julia 1.10"
+    Support for `memmove` requires at least Julia 1.10.
+
+"""
+function memmove(dst::Ptr, src::Ptr, n::Integer)
+    ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
+end
+
+"""
+    memset(dst::Ptr, val, n::Integer) -> Ptr{Cvoid}
+
+Call `memset` from the C standard library.
+
+!!! compat "Julia 1.10"
+    Support for `memset` requires at least Julia 1.10.
+
+"""
+function memset(p::Ptr, val, n::Integer)
+    ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), p, val, n)
+end
+
+"""
+    memcmp(a::Ptr, b::Ptr, n::Integer) -> Int
+
+Call `memcmp` from the C standard library.
+
+!!! compat "Julia 1.10"
+    Support for `memcmp` requires at least Julia 1.9.
+
+"""
+function memcmp(a::Ptr, b::Ptr, n::Integer)
+    ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, n % Csize_t) % Int
+end
+
diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl
index 74814733f088d..58f77078ddb5e 100644
--- a/base/compiler/compiler.jl
+++ b/base/compiler/compiler.jl
@@ -100,6 +100,7 @@ add_with_overflow(x::T, y::T) where {T<:SignedInt}   = checked_sadd_int(x, y)
 add_with_overflow(x::T, y::T) where {T<:UnsignedInt} = checked_uadd_int(x, y)
 add_with_overflow(x::Bool, y::Bool) = (x+y, false)
 
+include("cmem.jl")
 include("strings/lazy.jl")
 
 # core array operations
diff --git a/base/iddict.jl b/base/iddict.jl
index 99710fbb3491e..01ff213305d7b 100644
--- a/base/iddict.jl
+++ b/base/iddict.jl
@@ -134,7 +134,10 @@ end
 
 function empty!(d::IdDict)
     resize!(d.ht, 32)
-    ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), d.ht, 0, sizeof(d.ht))
+    ht = d.ht
+    t = @_gc_preserve_begin ht
+    memset(unsafe_convert(Ptr{Cvoid}, ht), 0, sizeof(ht))
+    @_gc_preserve_end t
     d.ndel = 0
     d.count = 0
     return d
diff --git a/base/libc.jl b/base/libc.jl
index 90c5b55127230..27266cfafb8ac 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -6,6 +6,8 @@ Interface to libc, the C standard library.
 """ Libc
 
 import Base: transcode, windowserror, show
+# these need to be defined seperately for bootstrapping but belong to Libc
+import Base: free, malloc, realloc, calloc, memcpy, memmove, memset, memcmp
 import Core.Intrinsics: bitcast
 
 export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, memcpy,
@@ -336,97 +338,6 @@ if Sys.iswindows()
     end
 end
 
-## Memory related ##
-
-"""
-    free(addr::Ptr)
-
-Call `free` from the C standard library. Only use this on memory obtained from [`malloc`](@ref), not
-on pointers retrieved from other C libraries. [`Ptr`](@ref) objects obtained from C libraries should
-be freed by the free functions defined in that library, to avoid assertion failures if
-multiple `libc` libraries exist on the system.
-"""
-free(p::Ptr) = ccall(:free, Cvoid, (Ptr{Cvoid},), p)
-
-"""
-    malloc(size::Integer) -> Ptr{Cvoid}
-
-Call `malloc` from the C standard library.
-"""
-malloc(size::Integer) = ccall(:malloc, Ptr{Cvoid}, (Csize_t,), size)
-
-"""
-    realloc(addr::Ptr, size::Integer) -> Ptr{Cvoid}
-
-Call `realloc` from the C standard library.
-
-See warning in the documentation for [`free`](@ref) regarding only using this on memory originally
-obtained from [`malloc`](@ref).
-"""
-realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), p, size)
-
-"""
-    calloc(num::Integer, size::Integer) -> Ptr{Cvoid}
-
-Call `calloc` from the C standard library.
-"""
-calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
-
-"""
-    memcpy(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
-
-Call `memcpy` from the C standard library.
-
-!!! compat "Julia 1.10"
-    Support for `memcpy` requires at least Julia 1.10.
-
-"""
-function memcpy(dst::Ptr, src::Ptr, n::Integer)
-    ccall(:memcpy, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
-end
-
-"""
-    memmove(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
-
-Call `memmove` from the C standard library.
-
-!!! compat "Julia 1.10"
-    Support for `memmove` requires at least Julia 1.10.
-
-"""
-function memmove(dst::Ptr, src::Ptr, n::Integer)
-    ccall(:memmove, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), dst, src, n)
-end
-
-"""
-    memset(dst::Ptr, val, n::Integer) -> Ptr{Cvoid}
-
-Call `memset` from the C standard library.
-
-!!! compat "Julia 1.10"
-    Support for `memset` requires at least Julia 1.10.
-
-"""
-function memset(p::Ptr, val, n::Integer)
-    ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), p, val, n)
-end
-
-"""
-    memcmp(a::Ptr, b::Ptr, n::Integer) -> Int
-
-Call `memcmp` from the C standard library.
-
-!!! compat "Julia 1.10"
-    Support for `memcmp` requires at least Julia 1.9.
-
-"""
-function memcmp(a::Ptr, b::Ptr, n::Integer)
-    ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, n % Csize_t) % Int
-end
-
-free(p::Cstring) = free(convert(Ptr{UInt8}, p))
-free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
-
 ## Random numbers ##
 
 # Access to very high quality (kernel) randomness
diff --git a/base/refpointer.jl b/base/refpointer.jl
index 0cb2df6d24bce..920166ed34a84 100644
--- a/base/refpointer.jl
+++ b/base/refpointer.jl
@@ -72,17 +72,6 @@ true
 """
 Ref
 
-# C NUL-terminated string pointers; these can be used in ccall
-# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
-# a check for embedded NUL chars in the string (to avoid silent truncation).
-if Int === Int64
-    primitive type Cstring  64 end
-    primitive type Cwstring 64 end
-else
-    primitive type Cstring  32 end
-    primitive type Cwstring 32 end
-end
-
 ### General Methods for Ref{T} type
 
 eltype(x::Type{<:Ref{T}}) where {T} = @isdefined(T) ? T : Any
diff --git a/base/strings/string.jl b/base/strings/string.jl
index 9716d06deefdf..809b7746fed62 100644
--- a/base/strings/string.jl
+++ b/base/strings/string.jl
@@ -542,7 +542,7 @@ function repeat(c::AbstractChar, r::Integer)
     s = _string_n(n*r)
     p = pointer(s)
     GC.@preserve s if n == 1
-        ccall(:memset, Ptr{Cvoid}, (Ptr{UInt8}, Cint, Csize_t), p, u % UInt8, r)
+        memset(p, u % UInt8, r)
     elseif n == 2
         p16 = reinterpret(Ptr{UInt16}, p)
         for i = 1:r
diff --git a/base/strings/substring.jl b/base/strings/substring.jl
index 6c169624c72f5..792925f24b12b 100644
--- a/base/strings/substring.jl
+++ b/base/strings/substring.jl
@@ -267,7 +267,7 @@ function repeat(s::Union{String, SubString{String}}, r::Integer)
     out = _string_n(n*r)
     if n == 1 # common case: repeating a single-byte string
         @inbounds b = codeunit(s, 1)
-        ccall(:memset, Ptr{Cvoid}, (Ptr{UInt8}, Cint, Csize_t), out, b, r)
+        memset(unsafe_convert(Ptr{UInt8}, out), b, r)
     else
         for i = 0:r-1
             GC.@preserve s out unsafe_copyto!(pointer(out, i*n+1), pointer(s), n)

From 004b799b868cfceddff0273631861ed276b43124 Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Fri, 12 May 2023 20:40:29 -0400
Subject: [PATCH 10/15] Fix DSFMT memcpy

---
 base/array.jl              | 53 +++++++++++++++++++++++++++++++++-----
 base/cmem.jl               |  1 -
 base/strings/string.jl     |  6 ++++-
 stdlib/Random/src/DSFMT.jl |  6 ++++-
 4 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/base/array.jl b/base/array.jl
index b075fc8536ac9..56f2915255e1b 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -464,7 +464,10 @@ end
 getindex(::Type{Any}) = Vector{Any}()
 
 function fill!(a::Union{Array{UInt8}, Array{Int8}}, x::Integer)
-    ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), a, x isa eltype(a) ? x : convert(eltype(a), x), length(a))
+    t = @_gc_preserve_begin a
+    p = unsafe_convert(Ptr{Cvoid}, a)
+    memset(p, x isa eltype(a) ? x : convert(eltype(a), x), length(a))
+    @_gc_preserve_end t
     return a
 end
 
@@ -1832,22 +1835,60 @@ function empty!(a::Vector)
 end
 
 _memcmp(a, b, len) = ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, len % Csize_t) % Int
+# function _memcmp(a, b, len)
+#     ta = @_gc_preserve_begin a
+#     tb = @_gc_preserve_begin b
+#     pa = unsafe_convert(Ptr{Cvoid}, a)
+#     pb = unsafe_convert(Ptr{Cvoid}, b)
+#     memcmp(pa, pb, len % Csize_t) % Int
+#     @_gc_preserve_end ta
+#     @_gc_preserve_end tb
+# end
 
 # use memcmp for cmp on byte arrays
 function cmp(a::Array{UInt8,1}, b::Array{UInt8,1})
-    c = _memcmp(a, b, min(length(a),length(b)))
+    ta = @_gc_preserve_begin a
+    tb = @_gc_preserve_begin b
+    pa = unsafe_convert(Ptr{Cvoid}, a)
+    pb = unsafe_convert(Ptr{Cvoid}, b)
+    c = memcmp(pa, pb, min(length(a),length(b)))
+    @_gc_preserve_end ta
+    @_gc_preserve_end tb
     return c < 0 ? -1 : c > 0 ? +1 : cmp(length(a),length(b))
 end
 
 const BitIntegerArray{N} = Union{map(T->Array{T,N}, BitInteger_types)...} where N
 # use memcmp for == on bit integer types
-==(a::Arr, b::Arr) where {Arr <: BitIntegerArray} =
-    size(a) == size(b) && 0 == _memcmp(a, b, sizeof(eltype(Arr)) * length(a))
+function ==(a::Arr, b::Arr) where {Arr <: BitIntegerArray}
+    if size(a) == size(b)
+        ta = @_gc_preserve_begin a
+        tb = @_gc_preserve_begin b
+        pa = unsafe_convert(Ptr{Cvoid}, a)
+        pb = unsafe_convert(Ptr{Cvoid}, b)
+        c = memcmp(pa, pb, sizeof(eltype(Arr)) * length(a))
+        @_gc_preserve_end ta
+        @_gc_preserve_end tb
+        return c == 0
+    else
+        return false
+    end
+end
 
-# this is ~20% faster than the generic implementation above for very small arrays
 function ==(a::Arr, b::Arr) where Arr <: BitIntegerArray{1}
     len = length(a)
-    len == length(b) && 0 == _memcmp(a, b, sizeof(eltype(Arr)) * len)
+    if len == length(b)
+        ta = @_gc_preserve_begin a
+        tb = @_gc_preserve_begin b
+        T = eltype(Arr)
+        pa = unsafe_convert(Ptr{T}, a)
+        pb = unsafe_convert(Ptr{T}, b)
+        c = memcmp(pa, pb, sizeof(T) * len)
+        @_gc_preserve_end ta
+        @_gc_preserve_end tb
+        return c == 0
+    else
+        return false
+    end
 end
 
 """
diff --git a/base/cmem.jl b/base/cmem.jl
index 04b8b1b38c0fa..eeca7b40bfe99 100644
--- a/base/cmem.jl
+++ b/base/cmem.jl
@@ -98,4 +98,3 @@ Call `memcmp` from the C standard library.
 function memcmp(a::Ptr, b::Ptr, n::Integer)
     ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, n % Csize_t) % Int
 end
-
diff --git a/base/strings/string.jl b/base/strings/string.jl
index 809b7746fed62..a26791958cd50 100644
--- a/base/strings/string.jl
+++ b/base/strings/string.jl
@@ -127,7 +127,11 @@ end
 
 _memcmp(a::Union{Ptr{UInt8},AbstractString}, b::Union{Ptr{UInt8},AbstractString}) = _memcmp(a, b, min(sizeof(a), sizeof(b)))
 function _memcmp(a::Union{Ptr{UInt8},AbstractString}, b::Union{Ptr{UInt8},AbstractString}, len::Int)
-    ccall(:memcmp, Cint, (Ptr{UInt8}, Ptr{UInt8}, Csize_t), a, b, len % Csize_t) % Int
+    GC.@preserve a b begin
+        pa = unsafe_convert(Ptr{UInt8}, a)
+        pb = unsafe_convert(Ptr{UInt8}, b)
+        memcmp(pa, pb, len % Csize_t) % Int
+    end
 end
 
 function cmp(a::String, b::String)
diff --git a/stdlib/Random/src/DSFMT.jl b/stdlib/Random/src/DSFMT.jl
index d3d7ce4a56a5d..4c5cb8c522667 100644
--- a/stdlib/Random/src/DSFMT.jl
+++ b/stdlib/Random/src/DSFMT.jl
@@ -194,7 +194,11 @@ function dsfmt_jump(s::DSFMT_state, jp::GF2X)
     work = zeros(Int32, JN32)
     rwork = reinterpret(UInt64, work)
     dsfmt = Vector{UInt64}(undef, nval >> 1)
-    memcpy(dsfmt, val, (nval - 1) * sizeof(Int32))
+    GC.@preserve dsfmt val begin
+        pdsfmt = Base.unsafe_convert(Ptr{Cvoid}, dsfmt)
+        pval = Base.unsafe_convert(Ptr{Cvoid}, val)
+        Base.Libc.memcpy(pdsfmt, pval, (nval - 1) * sizeof(Int32))
+    end
     dsfmt[end] = UInt64(N*2)
 
     for i in 0:degree(jp)

From a0f6f71e9a9b04af2ee7d9d4ae592fc73adfa30e Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Fri, 12 May 2023 21:51:56 -0400
Subject: [PATCH 11/15] Fix clipboard.jl memcpy

---
 stdlib/InteractiveUtils/src/clipboard.jl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/stdlib/InteractiveUtils/src/clipboard.jl b/stdlib/InteractiveUtils/src/clipboard.jl
index 2a0a707026671..c2abda9a60cc3 100644
--- a/stdlib/InteractiveUtils/src/clipboard.jl
+++ b/stdlib/InteractiveUtils/src/clipboard.jl
@@ -100,7 +100,7 @@ elseif Sys.iswindows()
         pdata == C_NULL && return cleanup(:GlobalAlloc)
         plock = ccall((:GlobalLock, "kernel32"), stdcall, Ptr{UInt16}, (Ptr{UInt16},), pdata)
         plock == C_NULL && return cleanup(:GlobalLock)
-        memcpy(plock, x_u16, sizeof(x_u16))
+        GC.@preserve x_u16 memcpy(plock, Base.unsafe_convert(Ptr{UInt16}, x_u16), sizeof(x_u16))
         unlock = ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{UInt16},), pdata)
         (unlock == 0 && Libc.GetLastError() == 0) || return cleanup(:GlobalUnlock) # this should never fail
         pset = ccall((:SetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint, Ptr{UInt16}), 13, pdata) # CF_UNICODETEXT

From de511f5bcc862b615b9d1c69a5f86a49b66ba2fa Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Sat, 13 May 2023 00:05:14 -0400
Subject: [PATCH 12/15] Replace pointer_to_objref

pointer_to_objref(::Array) is not same as unsafe_convert(Ptr, ::Array)
---
 stdlib/Random/src/XoshiroSimd.jl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index 6cc587773ee9f..0c9cdda38ca55 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -181,7 +181,7 @@ end
         s3 = _rotl45(s3)
         ref = Ref(f(res, T))
         # TODO: This may make the random-stream dependent on system endianness
-        GC.@preserve ref memcpy(dst+i, pointer_from_objref(ref), len-i)
+        GC.@preserve ref memcpy(dst+i, Base.unsafe_convert(Ptr{Cvoid}, ref), len-i)
     end
     if rng isa TaskLocalRNG
         task.rngState0, task.rngState1, task.rngState2, task.rngState3 = s0, s1, s2, s3
@@ -223,7 +223,7 @@ end
         res = _plus(_rotl23(_plus(s0,s3)),s0)
         resLoc = _and(res, 0x0101010101010101)
         ref = Ref(resLoc)
-        GC.@preserve ref memcpy(dst+i, pointer_from_objref(ref), len-i)
+        GC.@preserve ref memcpy(dst+i, Base.unsafe_convert(Ptr{Cvoid}, ref), len-i)
         t = _shl17(s1)
         s2 = _xor(s2, s0)
         s3 = _xor(s3, s1)

From 9997bf920b01a40410bd7281fc3fc552fd6dddd1 Mon Sep 17 00:00:00 2001
From: Zachary P Christensen <zchristensen7@gmail.com>
Date: Mon, 15 May 2023 14:43:00 -0400
Subject: [PATCH 13/15] Update base/array.jl

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
---
 base/array.jl | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/base/array.jl b/base/array.jl
index 56f2915255e1b..ff4eaf68f2988 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -1835,15 +1835,6 @@ function empty!(a::Vector)
 end
 
 _memcmp(a, b, len) = ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, len % Csize_t) % Int
-# function _memcmp(a, b, len)
-#     ta = @_gc_preserve_begin a
-#     tb = @_gc_preserve_begin b
-#     pa = unsafe_convert(Ptr{Cvoid}, a)
-#     pb = unsafe_convert(Ptr{Cvoid}, b)
-#     memcmp(pa, pb, len % Csize_t) % Int
-#     @_gc_preserve_end ta
-#     @_gc_preserve_end tb
-# end
 
 # use memcmp for cmp on byte arrays
 function cmp(a::Array{UInt8,1}, b::Array{UInt8,1})

From 71bf98e786a072834eda2d4e86d32ff9c1659abb Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Mon, 15 May 2023 22:51:33 -0400
Subject: [PATCH 14/15] Replace remaing `ccal(:memcmp, ...`

---
 base/array.jl                    | 2 --
 base/bitset.jl                   | 2 +-
 base/parse.jl                    | 8 +++++---
 stdlib/Random/src/Random.jl      | 1 -
 stdlib/Random/src/XoshiroSimd.jl | 2 +-
 5 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/base/array.jl b/base/array.jl
index ff4eaf68f2988..ce400a7fa7154 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -1834,8 +1834,6 @@ function empty!(a::Vector)
     return a
 end
 
-_memcmp(a, b, len) = ccall(:memcmp, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t), a, b, len % Csize_t) % Int
-
 # use memcmp for cmp on byte arrays
 function cmp(a::Array{UInt8,1}, b::Array{UInt8,1})
     ta = @_gc_preserve_begin a
diff --git a/base/bitset.jl b/base/bitset.jl
index 5ce07389c771e..240be822fa263 100644
--- a/base/bitset.jl
+++ b/base/bitset.jl
@@ -391,7 +391,7 @@ function ==(s1::BitSet, s2::BitSet)
     if overlap > 0
         t1 = @_gc_preserve_begin a1
         t2 = @_gc_preserve_begin a2
-        _memcmp(pointer(a1, b2-b1+1), pointer(a2), overlap<<3) == 0 || return false
+        memcmp(pointer(a1, b2-b1+1), pointer(a2), overlap<<3) == 0 || return false
         @_gc_preserve_end t2
         @_gc_preserve_end t1
     end
diff --git a/base/parse.jl b/base/parse.jl
index d800e54258b0d..f6a93e56369b7 100644
--- a/base/parse.jl
+++ b/base/parse.jl
@@ -210,9 +210,11 @@ function tryparse_internal(::Type{Bool}, sbuff::AbstractString,
     len = endpos - startpos + 1
     if sbuff isa Union{String, SubString{String}}
         p = pointer(sbuff) + startpos - 1
-        GC.@preserve sbuff begin
-            (len == 4) && (0 == _memcmp(p, "true", 4)) && (return true)
-            (len == 5) && (0 == _memcmp(p, "false", 5)) && (return false)
+        truestr = "true"
+        falsestr = "false"
+        GC.@preserve sbuff truestr falsestr begin
+            (len == 4) && (0 == memcmp(p, unsafe_convert(Ptr{UInt8}, truestr), 4)) && (return true)
+            (len == 5) && (0 == memcmp(p, unsafe_convert(Ptr{UInt8}, falsestr), 5)) && (return false)
         end
     else
         (len == 4) && (SubString(sbuff, startpos:startpos+3) == "true") && (return true)
diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl
index 7c13c63e208e1..89bb51516c106 100644
--- a/stdlib/Random/src/Random.jl
+++ b/stdlib/Random/src/Random.jl
@@ -16,7 +16,6 @@ using Base.GMP: Limb
 import SHA
 
 using Base: BitInteger, BitInteger_types, BitUnsigned, require_one_based_indexing
-using Base.Libc
 import Base: copymutable, copy, copy!, ==, hash, convert,
              rand, randn, show
 
diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl
index 0c9cdda38ca55..1a16baa4bce28 100644
--- a/stdlib/Random/src/XoshiroSimd.jl
+++ b/stdlib/Random/src/XoshiroSimd.jl
@@ -5,7 +5,7 @@ module XoshiroSimd
 import ..Random: TaskLocalRNG, rand, rand!, Xoshiro, CloseOpen01, UnsafeView,
                  SamplerType, SamplerTrivial
 using Base: BitInteger_types
-using Base.Libc
+using Base.Libc: memcpy
 using Core.Intrinsics: llvmcall
 
 # Vector-width. Influences random stream.

From 1c14e64b9818b748b6d490ff99ea2c4621a0a15b Mon Sep 17 00:00:00 2001
From: "Zachary P. Christensen" <zchristensen7@gmail.com>
Date: Mon, 22 May 2023 15:27:12 -0400
Subject: [PATCH 15/15] Move c-mem fxns back

---
 base/cmem.jl       | 47 ----------------------------------------------
 base/libc.jl       | 41 +++++++++++++++++++++++++++++++++++++++-
 base/refpointer.jl | 12 ++++++++++++
 3 files changed, 52 insertions(+), 48 deletions(-)

diff --git a/base/cmem.jl b/base/cmem.jl
index eeca7b40bfe99..8b0b99b3a6ebd 100644
--- a/base/cmem.jl
+++ b/base/cmem.jl
@@ -1,52 +1,5 @@
 # This file is a part of Julia. License is MIT: https://julialang.org/license
 
-# C NUL-terminated string pointers; these can be used in ccall
-# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
-# a check for embedded NUL chars in the string (to avoid silent truncation).
-if Int === Int64
-    primitive type Cstring  64 end
-    primitive type Cwstring 64 end
-else
-    primitive type Cstring  32 end
-    primitive type Cwstring 32 end
-end
-
-"""
-    free(addr::Ptr)
-
-Call `free` from the C standard library. Only use this on memory obtained from [`malloc`](@ref), not
-on pointers retrieved from other C libraries. [`Ptr`](@ref) objects obtained from C libraries should
-be freed by the free functions defined in that library, to avoid assertion failures if
-multiple `libc` libraries exist on the system.
-"""
-free(p::Ptr) = ccall(:free, Cvoid, (Ptr{Cvoid},), p)
-free(p::Cstring) = free(convert(Ptr{UInt8}, p))
-free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
-
-"""
-    malloc(size::Integer) -> Ptr{Cvoid}
-
-Call `malloc` from the C standard library.
-"""
-malloc(size::Integer) = ccall(:malloc, Ptr{Cvoid}, (Csize_t,), size)
-
-"""
-    realloc(addr::Ptr, size::Integer) -> Ptr{Cvoid}
-
-Call `realloc` from the C standard library.
-
-See warning in the documentation for [`free`](@ref) regarding only using this on memory originally
-obtained from [`malloc`](@ref).
-"""
-realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), p, size)
-
-"""
-    calloc(num::Integer, size::Integer) -> Ptr{Cvoid}
-
-Call `calloc` from the C standard library.
-"""
-calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
-
 """
     memcpy(dst::Ptr, src::Ptr, n::Integer) -> Ptr{Cvoid}
 
diff --git a/base/libc.jl b/base/libc.jl
index 27266cfafb8ac..99e8dce6b87e5 100644
--- a/base/libc.jl
+++ b/base/libc.jl
@@ -7,7 +7,7 @@ Interface to libc, the C standard library.
 
 import Base: transcode, windowserror, show
 # these need to be defined seperately for bootstrapping but belong to Libc
-import Base: free, malloc, realloc, calloc, memcpy, memmove, memset, memcmp
+import Base: memcpy, memmove, memset, memcmp
 import Core.Intrinsics: bitcast
 
 export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, memcpy,
@@ -338,6 +338,45 @@ if Sys.iswindows()
     end
 end
 
+## Memory related ##
+"""
+    free(addr::Ptr)
+
+Call `free` from the C standard library. Only use this on memory obtained from [`malloc`](@ref), not
+on pointers retrieved from other C libraries. [`Ptr`](@ref) objects obtained from C libraries should
+be freed by the free functions defined in that library, to avoid assertion failures if
+multiple `libc` libraries exist on the system.
+"""
+free(p::Ptr) = ccall(:free, Cvoid, (Ptr{Cvoid},), p)
+free(p::Cstring) = free(convert(Ptr{UInt8}, p))
+free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
+
+"""
+    malloc(size::Integer) -> Ptr{Cvoid}
+
+Call `malloc` from the C standard library.
+"""
+malloc(size::Integer) = ccall(:malloc, Ptr{Cvoid}, (Csize_t,), size)
+
+"""
+    realloc(addr::Ptr, size::Integer) -> Ptr{Cvoid}
+
+Call `realloc` from the C standard library.
+
+See warning in the documentation for [`free`](@ref) regarding only using this on memory originally
+obtained from [`malloc`](@ref).
+"""
+realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), p, size)
+
+"""
+    calloc(num::Integer, size::Integer) -> Ptr{Cvoid}
+
+Call `calloc` from the C standard library.
+"""
+calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
+
+
+
 ## Random numbers ##
 
 # Access to very high quality (kernel) randomness
diff --git a/base/refpointer.jl b/base/refpointer.jl
index 920166ed34a84..ad74763ff8286 100644
--- a/base/refpointer.jl
+++ b/base/refpointer.jl
@@ -72,6 +72,18 @@ true
 """
 Ref
 
+# C NUL-terminated string pointers; these can be used in ccall
+# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
+# a check for embedded NUL chars in the string (to avoid silent truncation).
+if Int === Int64
+    primitive type Cstring  64 end
+    primitive type Cwstring 64 end
+else
+    primitive type Cstring  32 end
+    primitive type Cwstring 32 end
+end
+
+
 ### General Methods for Ref{T} type
 
 eltype(x::Type{<:Ref{T}}) where {T} = @isdefined(T) ? T : Any