[RFC PATCH 1/1] MdePkg: Add a libc implementation


Pedro Falcato
 

Add LibcLib, a libc implementation meant to centralize all libc bits in
edk2.

Work in progress, does not support Windows targets (CLANGPDB and MSVC)
just yet.

Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <gaoliming@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Benny Lin <benny.lin@...>
Signed-off-by: Pedro Falcato <pedro.falcato@...>
---
Wrote this to fulfill the new needs for BaseFdtLib and libfdt.
It's very much a work in progress. Please test (I have no way to test this,
and I have not attempted to replace OpenSSL stuff just yet). It's not perfect,
but I attempted to be as correct as possible. Please, comment.

Some details:
1) I attempted to be as standards-correct as possible, used __name and _Name to avoid namespace polution.
I (unfortunately) had to include Base.h for NULL, because defining my own would possibly spell disaster
if someone included a C standard header and Base.h.
2) ProcessorBind.h implicitly polutes the global namespace. I don't think this is fixable.
3) In some places, I wrote my own functions when I could redirect to BaseMemoryLib stuff.
The amount of possible points of failure made me nervous (max string size PCD, etc). To be discussed.
4) This should fulfill BaseFdtLib's needs. I went a bit more in-depth where I could (without wasting too much time).
Of course, this means it's still missing a *HUGE* chunk of libc. I don't think I'm aiming to write a full libc here (haha).
Just the common bits that may be useful for edk2.
5) As discussed before (in the context of compiler intrinsics), GCC and clang require memcpy, memset, and some others for valid
codegen. This should possibly be done implicitly by BaseTools.
6) Again, please, comment or contribute. If anyone wants to send PRs or checkout directly, feel free: https://github.com/heatd/edk2/tree/wip-libc

MdePkg/Include/limits.h | 69 ++++++++++++++
MdePkg/Include/stdbool.h | 17 ++++
MdePkg/Include/stddef.h | 26 +++++
MdePkg/Include/stdint.h | 116 +++++++++++++++++++++++
MdePkg/Include/stdlib.h | 21 ++++
MdePkg/Include/string.h | 86 +++++++++++++++++
MdePkg/Include/types.h | 27 ++++++
MdePkg/Library/LibcLib/LibcLib.inf | 38 ++++++++
MdePkg/Library/LibcLib/Stdlib/strtoul.c | 121 ++++++++++++++++++++++++
MdePkg/Library/LibcLib/String/memchr.c | 19 ++++
MdePkg/Library/LibcLib/String/memcmp.c | 19 ++++
MdePkg/Library/LibcLib/String/memcpy.c | 29 ++++++
MdePkg/Library/LibcLib/String/memset.c | 21 ++++
MdePkg/Library/LibcLib/String/strchr.c | 56 +++++++++++
MdePkg/Library/LibcLib/String/strcmp.c | 27 ++++++
MdePkg/Library/LibcLib/String/strcpy.c | 59 ++++++++++++
MdePkg/Library/LibcLib/String/strlen.c | 16 ++++
MdePkg/MdeLibs.dsc.inc | 1 +
MdePkg/MdePkg.dec | 4 +
MdePkg/MdePkg.dsc | 1 +
20 files changed, 773 insertions(+)
create mode 100644 MdePkg/Include/limits.h
create mode 100644 MdePkg/Include/stdbool.h
create mode 100644 MdePkg/Include/stddef.h
create mode 100644 MdePkg/Include/stdint.h
create mode 100644 MdePkg/Include/stdlib.h
create mode 100644 MdePkg/Include/string.h
create mode 100644 MdePkg/Include/types.h
create mode 100644 MdePkg/Library/LibcLib/LibcLib.inf
create mode 100644 MdePkg/Library/LibcLib/Stdlib/strtoul.c
create mode 100644 MdePkg/Library/LibcLib/String/memchr.c
create mode 100644 MdePkg/Library/LibcLib/String/memcmp.c
create mode 100644 MdePkg/Library/LibcLib/String/memcpy.c
create mode 100644 MdePkg/Library/LibcLib/String/memset.c
create mode 100644 MdePkg/Library/LibcLib/String/strchr.c
create mode 100644 MdePkg/Library/LibcLib/String/strcmp.c
create mode 100644 MdePkg/Library/LibcLib/String/strcpy.c
create mode 100644 MdePkg/Library/LibcLib/String/strlen.c

diff --git a/MdePkg/Include/limits.h b/MdePkg/Include/limits.h
new file mode 100644
index 000000000000..f87b870e6cbc
--- /dev/null
+++ b/MdePkg/Include/limits.h
@@ -0,0 +1,69 @@
+/** @file
+ ISO C limits.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#if defined (MDE_CPU_X64) || defined (MDE_CPU_AARCH64)
+// Hint for LONG_* stuff
+#define __LIMITS_64BIT
+#endif
+
+#ifndef __GNUC__
+// TODO: MSVC support is missing (some types are not exactly the same)
+// Should this whole logic be in ProcessorBind.h or something?
+ #error "MSVC support TODO"
+#endif
+
+#define CHAR_BIT 8
+
+/* Char limits - for char, signed char, unsigned char */
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+// Note: We must check if chars are signed or unsigned here. 0xff = -128 for signed chars
+#if '\xff' < 0
+#define __CHAR_IS_SIGNED
+#endif
+
+#ifdef __CHAR_IS_SIGNED
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+#else
+#define CHAR_MIN 0
+#define CHAR_MAX UCHAR_MAX
+#endif
+
+/* Short limits - for short, unsigned short */
+#define SHRT_MIN (-1 - 0x7fff)
+#define SHRT_MAX 0x7fff
+#define USHRT_MAX 0xffff
+
+/* Int limits - for int, unsigned int */
+#define INT_MIN (-1 - 0x7fffffff)
+#define INT_MAX 0x7fffffff
+#define UINT_MAX 0xffffffffU
+
+/* Long limits - for long, unsigned long and long long variants */
+
+#ifdef __LIMITS_64BIT
+#define LONG_MAX 0x7fffffffffffffffL
+#define LONG_MIN (-1 - 0x7fffffffffffffffL)
+#define ULONG_MAX 0xffffffffffffffffUL
+#else
+#define LONG_MAX 0x7fffffffL
+#define LONG_MIN (-1 - 0x7fffffffL)
+#define ULONG_MAX 0xffffffffUL
+#endif
+
+/* long long must always be 64-bit for EFI UINT64 */
+#define LLONG_MIN (-1 - 0x7fffffffffffffffLL)
+#define LLONG_MAX 0x7fffffffffffffffLL
+#define ULLONG_MAX 0xffffffffffffffffULL
+
+#endif
diff --git a/MdePkg/Include/stdbool.h b/MdePkg/Include/stdbool.h
new file mode 100644
index 000000000000..c365fbcc4f0f
--- /dev/null
+++ b/MdePkg/Include/stdbool.h
@@ -0,0 +1,17 @@
+/** @file
+ ISO C stdbool.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#define __bool_true_false_are_defined 1
+
+#endif
diff --git a/MdePkg/Include/stddef.h b/MdePkg/Include/stddef.h
new file mode 100644
index 000000000000..86c17102f4b2
--- /dev/null
+++ b/MdePkg/Include/stddef.h
@@ -0,0 +1,26 @@
+/** @file
+ ISO C stddef.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#include <Base.h> // For NULL
+// TODO: Namespace polution
+
+typedef INTN ptrdiff_t;
+typedef UINTN size_t;
+typedef CHAR16 wchar_t;
+
+// offsetof taken from Base.h
+
+#if (defined (__GNUC__) && __GNUC__ >= 4) || defined (__clang__)
+#define offsetof(TYPE, Field) ((UINTN) __builtin_offsetof(TYPE, Field))
+#else
+#define offsetof(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
+#endif
+
+#endif
diff --git a/MdePkg/Include/stdint.h b/MdePkg/Include/stdint.h
new file mode 100644
index 000000000000..ed554ff1773d
--- /dev/null
+++ b/MdePkg/Include/stdint.h
@@ -0,0 +1,116 @@
+/** @file
+ ISO C stdint.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+// INT(N), UINT(N) taken from ProcessorBind.h
+typedef INT8 int8_t;
+typedef INT16 int16_t;
+typedef INT32 int32_t;
+typedef INT64 int64_t;
+
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
+
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+typedef INTN intptr_t;
+typedef UINTN uintptr_t;
+
+typedef INT64 intmax_t;
+typedef UINT64 uintmax_t;
+
+/* Limits for the types declared above */
+#define INT8_MIN -128
+#define INT8_MAX 127
+#define UINT8_MAX 255
+#define INT16_MIN (-1 - 0x7fff)
+#define INT16_MAX 0x7fff
+#define UINT16_MAX 0xffff
+#define INT32_MIN (-1 - 0x7fffffff)
+#define INT32_MAX 0x7fffffff
+#define UINT32_MAX 0xffffffffU
+#define INT64_MIN (-1 - 0x7fffffffffffffffLL)
+#define INT64_MAX 0x7fffffffffffffffLL
+#define UINT64_MAX 0xffffffffffffffffULL
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTPTR_MIN (1 - MAX_INTN)
+#define INTPTR_MAX MAX_INTN
+#define UINTPTR_MAX MAX_UINTN
+
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INTPTR_MIN
+#define PTRDIFF_MAX INTPTR_MAX
+#define SIZE_MAX MAX_UINTN
+
+// TODO: SIG_ATOMIC, WCHAR, WINT
+
+/* Macros to declare (u)int(N)_t constants */
+
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) c ## LL
+#define UINT8_C(c) c
+#define UINT16_C(c) c
+#define UINT32_C(c) c ## U
+#define UINT64_C(c) c ## ULL
+
+#define INTMAX_C(c) c ## LL
+#define UINTMAX_C(c) c ## ULL
+
+#endif
diff --git a/MdePkg/Include/stdlib.h b/MdePkg/Include/stdlib.h
new file mode 100644
index 000000000000..954da4bbea8e
--- /dev/null
+++ b/MdePkg/Include/stdlib.h
@@ -0,0 +1,21 @@
+/** @file
+ ISO C stdlib.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#define __NEED_NULL
+#include <types.h>
+
+unsigned long
+strtoul (
+ const char *Nptr,
+ char **EndPtr,
+ int Base
+ );
+
+#endif
diff --git a/MdePkg/Include/string.h b/MdePkg/Include/string.h
new file mode 100644
index 000000000000..31d95db91cfe
--- /dev/null
+++ b/MdePkg/Include/string.h
@@ -0,0 +1,86 @@
+/** @file
+ ISO C string.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#define __NEED_size_t
+#define __NEED_NULL
+#include <types.h>
+
+void *
+memcpy (
+ void *restrict Dst,
+ const void *restrict Src,
+ size_t Count
+ );
+
+void *
+memmove (
+ void *Dst,
+ const void *Src,
+ size_t Count
+ );
+
+void *
+memset (
+ void *Buf,
+ int Val,
+ size_t Count
+ );
+
+void *
+memchr (
+ const void *Buf,
+ int Char,
+ size_t Count
+ );
+
+int
+memcmp (
+ const void *S1,
+ const void *S2,
+ size_t Count
+ );
+
+size_t
+strlen (
+ const char *Str
+ );
+
+char *
+strcpy (
+ char *restrict Dest,
+ const char *restrict Source
+ );
+
+char *
+strncpy (
+ char *restrict Dest,
+ const char *restrict Source,
+ size_t Count
+ );
+
+char *
+strcat (
+ char *restrict Dest,
+ const char *restrict Source
+ );
+
+char *
+strchr (
+ const char *Str,
+ int Char
+ );
+
+char *
+strrchr (
+ const char *Str,
+ int Char
+ );
+
+#endif
diff --git a/MdePkg/Include/types.h b/MdePkg/Include/types.h
new file mode 100644
index 000000000000..97e90d7b31e3
--- /dev/null
+++ b/MdePkg/Include/types.h
@@ -0,0 +1,27 @@
+/** @file
+ ISO C auxiliary types file
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+/* C has a variety of types we must define in a lot of header files, without
+ including the "canonical" header file due to namespace pollution reasons.
+ So define them here and use __NEED_ macros to ask for certain definitions.
+ */
+
+#if defined (__NEED_size_t) && !defined (__defined_size_t)
+typedef UINTN size_t;
+#define __defined_size_t
+#endif
+
+#if defined (__NEED_NULL) && !defined (__defined_NULL)
+ #include <Base.h>
+#define __defined_NULL
+// TODO: Namespace pollution
+#endif
+
+#endif
diff --git a/MdePkg/Library/LibcLib/LibcLib.inf b/MdePkg/Library/LibcLib/LibcLib.inf
new file mode 100644
index 000000000000..d15def794973
--- /dev/null
+++ b/MdePkg/Library/LibcLib/LibcLib.inf
@@ -0,0 +1,38 @@
+## @file
+# ISO C libc implementation for EDK2 modules
+#
+# Copyright (c) 2023 Pedro Falcato All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = LibcLib
+ FILE_GUID = 469201d7-0884-497a-ba93-ec5ee911b0e8
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LibcLib|BASE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ String/strcpy.c
+ String/strcmp.c
+ String/strlen.c
+ String/strchr.c
+ String/memcpy.c
+ String/memset.c
+ String/memchr.c
+ String/memcmp.c
+ Stdlib/strtoul.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
diff --git a/MdePkg/Library/LibcLib/Stdlib/strtoul.c b/MdePkg/Library/LibcLib/Stdlib/strtoul.c
new file mode 100644
index 000000000000..952d3b899c5e
--- /dev/null
+++ b/MdePkg/Library/LibcLib/Stdlib/strtoul.c
@@ -0,0 +1,121 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <stdlib.h>
+#include <limits.h>
+
+STATIC
+int
+__isspace (
+ int ch
+ )
+{
+ // basic ASCII ctype.h:isspace(). Not efficient
+ return ch == '\r' || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f';
+}
+
+unsigned long
+strtoul (
+ const char *Nptr,
+ char **EndPtr,
+ int Base
+ )
+{
+ BOOLEAN Negate;
+ BOOLEAN Overflow;
+ unsigned long Val;
+
+ Negate = FALSE;
+ Overflow = FALSE;
+ Val = 0;
+
+ // Reject bad numeric bases
+ if ((Base < 0) || (Base == 1) || (Base > 36)) {
+ return 0;
+ }
+
+ // Skip whitespace
+ while (__isspace (*Nptr)) {
+ Nptr++;
+ }
+
+ // Check for + or - prefixes
+ if (*Nptr == '-') {
+ Negate = TRUE;
+ Nptr++;
+ } else if (*Nptr == '+') {
+ Nptr++;
+ }
+
+ // Consume the start, autodetecting base if needed
+ if ((Nptr[0] == '0') && ((Nptr[1] == 'x') || (Nptr[1] == 'X')) && ((Base == 0) || (Base == 16))) {
+ // Hex
+ Nptr += 2;
+ Base = 16;
+ } else if ((Nptr[0] == '0') && ((Nptr[1] == 'b') || (Nptr[1] == 'B')) && ((Base == 0) || (Base == 2))) {
+ // Binary (standard pending C23)
+ Nptr += 2;
+ Base = 2;
+ } else if ((Nptr[0] == '0') && ((Base == 0) || (Base == 8))) {
+ // Octal
+ Nptr++;
+ Base = 8;
+ } else {
+ if (Base == 0) {
+ // Assume decimal
+ Base = 10;
+ }
+ }
+
+ while (TRUE) {
+ int Digit;
+ char C;
+ unsigned long NewVal;
+
+ C = *Nptr;
+ Digit = -1;
+
+ if ((C >= '0') && (C <= '9')) {
+ Digit = C - '0';
+ } else if ((C >= 'a') && (C <= 'z')) {
+ Digit = C - 'a' + 10;
+ } else if ((C >= 'A') && (C <= 'Z')) {
+ Digit = C - 'A' + 10;
+ }
+
+ if ((Digit == -1) || (Digit >= Base)) {
+ // Note that this case also handles the \0
+ if (EndPtr) {
+ *EndPtr = (char *)Nptr;
+ }
+
+ break;
+ }
+
+ NewVal = Val * Base + Digit;
+
+ if (NewVal < Val) {
+ // Overflow
+ Overflow = TRUE;
+ }
+
+ Val = NewVal;
+
+ Nptr++;
+ }
+
+ if (Negate) {
+ Val = -Val;
+ }
+
+ if (Overflow) {
+ Val = ULONG_MAX;
+ }
+
+ // TODO: We're lacking errno here.
+ return Val;
+}
diff --git a/MdePkg/Library/LibcLib/String/memchr.c b/MdePkg/Library/LibcLib/String/memchr.c
new file mode 100644
index 000000000000..cea8b71349f0
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memchr.c
@@ -0,0 +1,19 @@
+/** @file
+ memchr-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memchr (
+ const void *Buf,
+ int Char,
+ size_t Count
+ )
+{
+ return ScanMem8 (Buf, Count, Char);
+}
diff --git a/MdePkg/Library/LibcLib/String/memcmp.c b/MdePkg/Library/LibcLib/String/memcmp.c
new file mode 100644
index 000000000000..d02aa5d980f7
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memcmp.c
@@ -0,0 +1,19 @@
+/** @file
+ memcmp-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+int
+memcmp (
+ const void *S1,
+ const void *S2,
+ size_t Count
+ )
+{
+ return (int)CompareMem (S1, S2, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/memcpy.c b/MdePkg/Library/LibcLib/String/memcpy.c
new file mode 100644
index 000000000000..d6e85f7eb37f
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memcpy.c
@@ -0,0 +1,29 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memcpy (
+ void *restrict Dst,
+ const void *restrict Src,
+ size_t Count
+ )
+{
+ return CopyMem (Dst, Src, Count);
+}
+
+void *
+memmove (
+ void *Dst,
+ const void *Src,
+ size_t Count
+ )
+{
+ return CopyMem (Dst, Src, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/memset.c b/MdePkg/Library/LibcLib/String/memset.c
new file mode 100644
index 000000000000..e66d6ade5582
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memset.c
@@ -0,0 +1,21 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memset (
+ void *Buf,
+ int Val,
+ size_t Count
+ )
+{
+ // The standard defines memset as converting Val into an unsigned char before storing,
+ // so this cast is entirely safe.
+ return SetMem (Buf, Count, (UINT8)Val);
+}
diff --git a/MdePkg/Library/LibcLib/String/strchr.c b/MdePkg/Library/LibcLib/String/strchr.c
new file mode 100644
index 000000000000..5e0ce7c43c98
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strchr.c
@@ -0,0 +1,56 @@
+/** @file
+ strchr-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Base.h>
+
+// Very quick notes:
+// We only go through the string once for both functions
+// They are minimal implementations (not speed optimized) of ISO C semantics
+// strchr and strrchr also include the null terminator as part of the string
+// so the code gets a bit clunky to handle that case specifically.
+
+char *
+strchr (
+ const char *Str,
+ int Char
+ )
+{
+ char *S;
+
+ S = (char *)Str;
+
+ for ( ; ; S++) {
+ if (*S == Char) {
+ return S;
+ }
+
+ if (*S == '\0') {
+ return NULL;
+ }
+ }
+}
+
+char *
+strrchr (
+ const char *Str,
+ int Char
+ )
+{
+ char *S, *last;
+
+ S = (char *)Str;
+ last = NULL;
+
+ for ( ; ; S++) {
+ if (*S == Char) {
+ last = S;
+ }
+
+ if (*S == '\0') {
+ return last;
+ }
+ }
+}
diff --git a/MdePkg/Library/LibcLib/String/strcmp.c b/MdePkg/Library/LibcLib/String/strcmp.c
new file mode 100644
index 000000000000..9561fad389d3
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strcmp.c
@@ -0,0 +1,27 @@
+/** @file
+ strcmp-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+
+int
+strcmp (
+ const char *Str1,
+ const char *Str2
+ )
+{
+ return (int)AsciiStrCmp (Str1, Str2);
+}
+
+int
+strncmp (
+ const char *Str1,
+ const char *Str2,
+ size_t Count
+ )
+{
+ return (int)AsciiStrnCmp (Str1, Str2, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/strcpy.c b/MdePkg/Library/LibcLib/String/strcpy.c
new file mode 100644
index 000000000000..767c18d6a464
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strcpy.c
@@ -0,0 +1,59 @@
+/** @file
+ strcpy-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+char *
+strcpy (
+ char *restrict Dest,
+ const char *restrict Source
+ )
+{
+ char *Ret;
+
+ Ret = Dest;
+
+ for ( ; *Source != '\0'; Source++, Dest++) {
+ *Dest = *Source;
+ }
+
+ *Dest = '\0';
+
+ return Ret;
+}
+
+char *
+strncpy (
+ char *restrict Dest,
+ const char *restrict Source,
+ size_t Count
+ )
+{
+ char *Ret;
+
+ Ret = Dest;
+
+ while (Count--) {
+ if (*Source != '\0') {
+ *Dest++ = *Source++;
+ } else {
+ *Dest++ = '\0';
+ }
+ }
+
+ return Ret;
+}
+
+char *
+strcat (
+ char *restrict Dest,
+ const char *restrict Source
+ )
+{
+ return strcpy (Dest + strlen (Dest), Source);
+}
diff --git a/MdePkg/Library/LibcLib/String/strlen.c b/MdePkg/Library/LibcLib/String/strlen.c
new file mode 100644
index 000000000000..a95fb7a18f7b
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strlen.c
@@ -0,0 +1,16 @@
+/** @file
+ strlen implementation
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+
+size_t
+strlen (
+ const char *Str
+ )
+{
+ return AsciiStrLen (Str);
+}
diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc
index 4580481cb580..f17d79286ec4 100644
--- a/MdePkg/MdeLibs.dsc.inc
+++ b/MdePkg/MdeLibs.dsc.inc
@@ -16,3 +16,4 @@
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
SmmCpuRendezvousLib|MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
+ LibcLib|MdePkg/Library/LibcLib/LibcLib.inf
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index e49b2d5b5f28..8c37d89f5418 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -284,6 +284,10 @@
#
ArmTrngLib|Include/Library/ArmTrngLib.h

+ ## @libraryclass Provides various bits of a C standard library.
+ #
+ LibcLib|MdePkg/Library/LibcLib/LibcLib.inf
+
[LibraryClasses.IA32, LibraryClasses.X64, LibraryClasses.AARCH64]
## @libraryclass Provides services to generate random number.
#
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index 32a852dc466e..09828ae12647 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -135,6 +135,7 @@
MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
MdePkg/Library/CcProbeLibNull/CcProbeLibNull.inf
MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
+ MdePkg/Library/LibcLib/LibcLib.inf

[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
#
--
2.40.0


Gerd Hoffmann
 

Hi,

Work in progress, does not support Windows targets (CLANGPDB and MSVC)
just yet.
The header files CryptoPkg has for openssl would be probably a good
starting point (instead of starting over from scratch ...).

take care,
Gerd


Michael D Kinney
 

Hi Pedro,

Thank you for starting this.

I recall some challenges with the Openssl libc wrapper, so let's work on that one last.

If we can get a libc wrapper that is compatible with Brotli, regular expression,
jannson, and fdtlib that would be a huge step forward.

Can you test your code against these 3 use cases that are already in edk2?

* MdeModulePkg\Library\BrotliCustomDecompressLib
* MdeModulePkg\Universal\RegularExpressionDxe
* RedfishPkg\PrivateInclude\Crt

Mike

-----Original Message-----
From: Pedro Falcato <pedro.falcato@...>
Sent: Thursday, March 30, 2023 7:31 PM
To: devel@edk2.groups.io
Cc: Pedro Falcato <pedro.falcato@...>; Kinney, Michael D <michael.d.kinney@...>; Gao, Liming
<gaoliming@...>; Liu, Zhiguang <zhiguang.liu@...>; Lin, Benny <benny.lin@...>
Subject: [RFC PATCH 1/1] MdePkg: Add a libc implementation

Add LibcLib, a libc implementation meant to centralize all libc bits in
edk2.

Work in progress, does not support Windows targets (CLANGPDB and MSVC)
just yet.

Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <gaoliming@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Benny Lin <benny.lin@...>
Signed-off-by: Pedro Falcato <pedro.falcato@...>
---
Wrote this to fulfill the new needs for BaseFdtLib and libfdt.
It's very much a work in progress. Please test (I have no way to test this,
and I have not attempted to replace OpenSSL stuff just yet). It's not perfect,
but I attempted to be as correct as possible. Please, comment.

Some details:
1) I attempted to be as standards-correct as possible, used __name and _Name to avoid namespace polution.
I (unfortunately) had to include Base.h for NULL, because defining my own would possibly spell disaster
if someone included a C standard header and Base.h.
2) ProcessorBind.h implicitly polutes the global namespace. I don't think this is fixable.
3) In some places, I wrote my own functions when I could redirect to BaseMemoryLib stuff.
The amount of possible points of failure made me nervous (max string size PCD, etc). To be discussed.
4) This should fulfill BaseFdtLib's needs. I went a bit more in-depth where I could (without wasting too much time).
Of course, this means it's still missing a *HUGE* chunk of libc. I don't think I'm aiming to write a full libc here
(haha).
Just the common bits that may be useful for edk2.
5) As discussed before (in the context of compiler intrinsics), GCC and clang require memcpy, memset, and some others for
valid
codegen. This should possibly be done implicitly by BaseTools.
6) Again, please, comment or contribute. If anyone wants to send PRs or checkout directly, feel free:
https://github.com/heatd/edk2/tree/wip-libc

MdePkg/Include/limits.h | 69 ++++++++++++++
MdePkg/Include/stdbool.h | 17 ++++
MdePkg/Include/stddef.h | 26 +++++
MdePkg/Include/stdint.h | 116 +++++++++++++++++++++++
MdePkg/Include/stdlib.h | 21 ++++
MdePkg/Include/string.h | 86 +++++++++++++++++
MdePkg/Include/types.h | 27 ++++++
MdePkg/Library/LibcLib/LibcLib.inf | 38 ++++++++
MdePkg/Library/LibcLib/Stdlib/strtoul.c | 121 ++++++++++++++++++++++++
MdePkg/Library/LibcLib/String/memchr.c | 19 ++++
MdePkg/Library/LibcLib/String/memcmp.c | 19 ++++
MdePkg/Library/LibcLib/String/memcpy.c | 29 ++++++
MdePkg/Library/LibcLib/String/memset.c | 21 ++++
MdePkg/Library/LibcLib/String/strchr.c | 56 +++++++++++
MdePkg/Library/LibcLib/String/strcmp.c | 27 ++++++
MdePkg/Library/LibcLib/String/strcpy.c | 59 ++++++++++++
MdePkg/Library/LibcLib/String/strlen.c | 16 ++++
MdePkg/MdeLibs.dsc.inc | 1 +
MdePkg/MdePkg.dec | 4 +
MdePkg/MdePkg.dsc | 1 +
20 files changed, 773 insertions(+)
create mode 100644 MdePkg/Include/limits.h
create mode 100644 MdePkg/Include/stdbool.h
create mode 100644 MdePkg/Include/stddef.h
create mode 100644 MdePkg/Include/stdint.h
create mode 100644 MdePkg/Include/stdlib.h
create mode 100644 MdePkg/Include/string.h
create mode 100644 MdePkg/Include/types.h
create mode 100644 MdePkg/Library/LibcLib/LibcLib.inf
create mode 100644 MdePkg/Library/LibcLib/Stdlib/strtoul.c
create mode 100644 MdePkg/Library/LibcLib/String/memchr.c
create mode 100644 MdePkg/Library/LibcLib/String/memcmp.c
create mode 100644 MdePkg/Library/LibcLib/String/memcpy.c
create mode 100644 MdePkg/Library/LibcLib/String/memset.c
create mode 100644 MdePkg/Library/LibcLib/String/strchr.c
create mode 100644 MdePkg/Library/LibcLib/String/strcmp.c
create mode 100644 MdePkg/Library/LibcLib/String/strcpy.c
create mode 100644 MdePkg/Library/LibcLib/String/strlen.c

diff --git a/MdePkg/Include/limits.h b/MdePkg/Include/limits.h
new file mode 100644
index 000000000000..f87b870e6cbc
--- /dev/null
+++ b/MdePkg/Include/limits.h
@@ -0,0 +1,69 @@
+/** @file
+ ISO C limits.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#if defined (MDE_CPU_X64) || defined (MDE_CPU_AARCH64)
+// Hint for LONG_* stuff
+#define __LIMITS_64BIT
+#endif
+
+#ifndef __GNUC__
+// TODO: MSVC support is missing (some types are not exactly the same)
+// Should this whole logic be in ProcessorBind.h or something?
+ #error "MSVC support TODO"
+#endif
+
+#define CHAR_BIT 8
+
+/* Char limits - for char, signed char, unsigned char */
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+// Note: We must check if chars are signed or unsigned here. 0xff = -128 for signed chars
+#if '\xff' < 0
+#define __CHAR_IS_SIGNED
+#endif
+
+#ifdef __CHAR_IS_SIGNED
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+#else
+#define CHAR_MIN 0
+#define CHAR_MAX UCHAR_MAX
+#endif
+
+/* Short limits - for short, unsigned short */
+#define SHRT_MIN (-1 - 0x7fff)
+#define SHRT_MAX 0x7fff
+#define USHRT_MAX 0xffff
+
+/* Int limits - for int, unsigned int */
+#define INT_MIN (-1 - 0x7fffffff)
+#define INT_MAX 0x7fffffff
+#define UINT_MAX 0xffffffffU
+
+/* Long limits - for long, unsigned long and long long variants */
+
+#ifdef __LIMITS_64BIT
+#define LONG_MAX 0x7fffffffffffffffL
+#define LONG_MIN (-1 - 0x7fffffffffffffffL)
+#define ULONG_MAX 0xffffffffffffffffUL
+#else
+#define LONG_MAX 0x7fffffffL
+#define LONG_MIN (-1 - 0x7fffffffL)
+#define ULONG_MAX 0xffffffffUL
+#endif
+
+/* long long must always be 64-bit for EFI UINT64 */
+#define LLONG_MIN (-1 - 0x7fffffffffffffffLL)
+#define LLONG_MAX 0x7fffffffffffffffLL
+#define ULLONG_MAX 0xffffffffffffffffULL
+
+#endif
diff --git a/MdePkg/Include/stdbool.h b/MdePkg/Include/stdbool.h
new file mode 100644
index 000000000000..c365fbcc4f0f
--- /dev/null
+++ b/MdePkg/Include/stdbool.h
@@ -0,0 +1,17 @@
+/** @file
+ ISO C stdbool.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#define __bool_true_false_are_defined 1
+
+#endif
diff --git a/MdePkg/Include/stddef.h b/MdePkg/Include/stddef.h
new file mode 100644
index 000000000000..86c17102f4b2
--- /dev/null
+++ b/MdePkg/Include/stddef.h
@@ -0,0 +1,26 @@
+/** @file
+ ISO C stddef.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#include <Base.h> // For NULL
+// TODO: Namespace polution
+
+typedef INTN ptrdiff_t;
+typedef UINTN size_t;
+typedef CHAR16 wchar_t;
+
+// offsetof taken from Base.h
+
+#if (defined (__GNUC__) && __GNUC__ >= 4) || defined (__clang__)
+#define offsetof(TYPE, Field) ((UINTN) __builtin_offsetof(TYPE, Field))
+#else
+#define offsetof(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
+#endif
+
+#endif
diff --git a/MdePkg/Include/stdint.h b/MdePkg/Include/stdint.h
new file mode 100644
index 000000000000..ed554ff1773d
--- /dev/null
+++ b/MdePkg/Include/stdint.h
@@ -0,0 +1,116 @@
+/** @file
+ ISO C stdint.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+// INT(N), UINT(N) taken from ProcessorBind.h
+typedef INT8 int8_t;
+typedef INT16 int16_t;
+typedef INT32 int32_t;
+typedef INT64 int64_t;
+
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
+
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+typedef INTN intptr_t;
+typedef UINTN uintptr_t;
+
+typedef INT64 intmax_t;
+typedef UINT64 uintmax_t;
+
+/* Limits for the types declared above */
+#define INT8_MIN -128
+#define INT8_MAX 127
+#define UINT8_MAX 255
+#define INT16_MIN (-1 - 0x7fff)
+#define INT16_MAX 0x7fff
+#define UINT16_MAX 0xffff
+#define INT32_MIN (-1 - 0x7fffffff)
+#define INT32_MAX 0x7fffffff
+#define UINT32_MAX 0xffffffffU
+#define INT64_MIN (-1 - 0x7fffffffffffffffLL)
+#define INT64_MAX 0x7fffffffffffffffLL
+#define UINT64_MAX 0xffffffffffffffffULL
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTPTR_MIN (1 - MAX_INTN)
+#define INTPTR_MAX MAX_INTN
+#define UINTPTR_MAX MAX_UINTN
+
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INTPTR_MIN
+#define PTRDIFF_MAX INTPTR_MAX
+#define SIZE_MAX MAX_UINTN
+
+// TODO: SIG_ATOMIC, WCHAR, WINT
+
+/* Macros to declare (u)int(N)_t constants */
+
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) c ## LL
+#define UINT8_C(c) c
+#define UINT16_C(c) c
+#define UINT32_C(c) c ## U
+#define UINT64_C(c) c ## ULL
+
+#define INTMAX_C(c) c ## LL
+#define UINTMAX_C(c) c ## ULL
+
+#endif
diff --git a/MdePkg/Include/stdlib.h b/MdePkg/Include/stdlib.h
new file mode 100644
index 000000000000..954da4bbea8e
--- /dev/null
+++ b/MdePkg/Include/stdlib.h
@@ -0,0 +1,21 @@
+/** @file
+ ISO C stdlib.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#define __NEED_NULL
+#include <types.h>
+
+unsigned long
+strtoul (
+ const char *Nptr,
+ char **EndPtr,
+ int Base
+ );
+
+#endif
diff --git a/MdePkg/Include/string.h b/MdePkg/Include/string.h
new file mode 100644
index 000000000000..31d95db91cfe
--- /dev/null
+++ b/MdePkg/Include/string.h
@@ -0,0 +1,86 @@
+/** @file
+ ISO C string.h
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#define __NEED_size_t
+#define __NEED_NULL
+#include <types.h>
+
+void *
+memcpy (
+ void *restrict Dst,
+ const void *restrict Src,
+ size_t Count
+ );
+
+void *
+memmove (
+ void *Dst,
+ const void *Src,
+ size_t Count
+ );
+
+void *
+memset (
+ void *Buf,
+ int Val,
+ size_t Count
+ );
+
+void *
+memchr (
+ const void *Buf,
+ int Char,
+ size_t Count
+ );
+
+int
+memcmp (
+ const void *S1,
+ const void *S2,
+ size_t Count
+ );
+
+size_t
+strlen (
+ const char *Str
+ );
+
+char *
+strcpy (
+ char *restrict Dest,
+ const char *restrict Source
+ );
+
+char *
+strncpy (
+ char *restrict Dest,
+ const char *restrict Source,
+ size_t Count
+ );
+
+char *
+strcat (
+ char *restrict Dest,
+ const char *restrict Source
+ );
+
+char *
+strchr (
+ const char *Str,
+ int Char
+ );
+
+char *
+strrchr (
+ const char *Str,
+ int Char
+ );
+
+#endif
diff --git a/MdePkg/Include/types.h b/MdePkg/Include/types.h
new file mode 100644
index 000000000000..97e90d7b31e3
--- /dev/null
+++ b/MdePkg/Include/types.h
@@ -0,0 +1,27 @@
+/** @file
+ ISO C auxiliary types file
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+/* C has a variety of types we must define in a lot of header files, without
+ including the "canonical" header file due to namespace pollution reasons.
+ So define them here and use __NEED_ macros to ask for certain definitions.
+ */
+
+#if defined (__NEED_size_t) && !defined (__defined_size_t)
+typedef UINTN size_t;
+#define __defined_size_t
+#endif
+
+#if defined (__NEED_NULL) && !defined (__defined_NULL)
+ #include <Base.h>
+#define __defined_NULL
+// TODO: Namespace pollution
+#endif
+
+#endif
diff --git a/MdePkg/Library/LibcLib/LibcLib.inf b/MdePkg/Library/LibcLib/LibcLib.inf
new file mode 100644
index 000000000000..d15def794973
--- /dev/null
+++ b/MdePkg/Library/LibcLib/LibcLib.inf
@@ -0,0 +1,38 @@
+## @file
+# ISO C libc implementation for EDK2 modules
+#
+# Copyright (c) 2023 Pedro Falcato All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = LibcLib
+ FILE_GUID = 469201d7-0884-497a-ba93-ec5ee911b0e8
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LibcLib|BASE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ String/strcpy.c
+ String/strcmp.c
+ String/strlen.c
+ String/strchr.c
+ String/memcpy.c
+ String/memset.c
+ String/memchr.c
+ String/memcmp.c
+ Stdlib/strtoul.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
diff --git a/MdePkg/Library/LibcLib/Stdlib/strtoul.c b/MdePkg/Library/LibcLib/Stdlib/strtoul.c
new file mode 100644
index 000000000000..952d3b899c5e
--- /dev/null
+++ b/MdePkg/Library/LibcLib/Stdlib/strtoul.c
@@ -0,0 +1,121 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <stdlib.h>
+#include <limits.h>
+
+STATIC
+int
+__isspace (
+ int ch
+ )
+{
+ // basic ASCII ctype.h:isspace(). Not efficient
+ return ch == '\r' || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f';
+}
+
+unsigned long
+strtoul (
+ const char *Nptr,
+ char **EndPtr,
+ int Base
+ )
+{
+ BOOLEAN Negate;
+ BOOLEAN Overflow;
+ unsigned long Val;
+
+ Negate = FALSE;
+ Overflow = FALSE;
+ Val = 0;
+
+ // Reject bad numeric bases
+ if ((Base < 0) || (Base == 1) || (Base > 36)) {
+ return 0;
+ }
+
+ // Skip whitespace
+ while (__isspace (*Nptr)) {
+ Nptr++;
+ }
+
+ // Check for + or - prefixes
+ if (*Nptr == '-') {
+ Negate = TRUE;
+ Nptr++;
+ } else if (*Nptr == '+') {
+ Nptr++;
+ }
+
+ // Consume the start, autodetecting base if needed
+ if ((Nptr[0] == '0') && ((Nptr[1] == 'x') || (Nptr[1] == 'X')) && ((Base == 0) || (Base == 16))) {
+ // Hex
+ Nptr += 2;
+ Base = 16;
+ } else if ((Nptr[0] == '0') && ((Nptr[1] == 'b') || (Nptr[1] == 'B')) && ((Base == 0) || (Base == 2))) {
+ // Binary (standard pending C23)
+ Nptr += 2;
+ Base = 2;
+ } else if ((Nptr[0] == '0') && ((Base == 0) || (Base == 8))) {
+ // Octal
+ Nptr++;
+ Base = 8;
+ } else {
+ if (Base == 0) {
+ // Assume decimal
+ Base = 10;
+ }
+ }
+
+ while (TRUE) {
+ int Digit;
+ char C;
+ unsigned long NewVal;
+
+ C = *Nptr;
+ Digit = -1;
+
+ if ((C >= '0') && (C <= '9')) {
+ Digit = C - '0';
+ } else if ((C >= 'a') && (C <= 'z')) {
+ Digit = C - 'a' + 10;
+ } else if ((C >= 'A') && (C <= 'Z')) {
+ Digit = C - 'A' + 10;
+ }
+
+ if ((Digit == -1) || (Digit >= Base)) {
+ // Note that this case also handles the \0
+ if (EndPtr) {
+ *EndPtr = (char *)Nptr;
+ }
+
+ break;
+ }
+
+ NewVal = Val * Base + Digit;
+
+ if (NewVal < Val) {
+ // Overflow
+ Overflow = TRUE;
+ }
+
+ Val = NewVal;
+
+ Nptr++;
+ }
+
+ if (Negate) {
+ Val = -Val;
+ }
+
+ if (Overflow) {
+ Val = ULONG_MAX;
+ }
+
+ // TODO: We're lacking errno here.
+ return Val;
+}
diff --git a/MdePkg/Library/LibcLib/String/memchr.c b/MdePkg/Library/LibcLib/String/memchr.c
new file mode 100644
index 000000000000..cea8b71349f0
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memchr.c
@@ -0,0 +1,19 @@
+/** @file
+ memchr-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memchr (
+ const void *Buf,
+ int Char,
+ size_t Count
+ )
+{
+ return ScanMem8 (Buf, Count, Char);
+}
diff --git a/MdePkg/Library/LibcLib/String/memcmp.c b/MdePkg/Library/LibcLib/String/memcmp.c
new file mode 100644
index 000000000000..d02aa5d980f7
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memcmp.c
@@ -0,0 +1,19 @@
+/** @file
+ memcmp-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+int
+memcmp (
+ const void *S1,
+ const void *S2,
+ size_t Count
+ )
+{
+ return (int)CompareMem (S1, S2, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/memcpy.c b/MdePkg/Library/LibcLib/String/memcpy.c
new file mode 100644
index 000000000000..d6e85f7eb37f
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memcpy.c
@@ -0,0 +1,29 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memcpy (
+ void *restrict Dst,
+ const void *restrict Src,
+ size_t Count
+ )
+{
+ return CopyMem (Dst, Src, Count);
+}
+
+void *
+memmove (
+ void *Dst,
+ const void *Src,
+ size_t Count
+ )
+{
+ return CopyMem (Dst, Src, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/memset.c b/MdePkg/Library/LibcLib/String/memset.c
new file mode 100644
index 000000000000..e66d6ade5582
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/memset.c
@@ -0,0 +1,21 @@
+/** @file
+ memcpy-like functions
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+
+void *
+memset (
+ void *Buf,
+ int Val,
+ size_t Count
+ )
+{
+ // The standard defines memset as converting Val into an unsigned char before storing,
+ // so this cast is entirely safe.
+ return SetMem (Buf, Count, (UINT8)Val);
+}
diff --git a/MdePkg/Library/LibcLib/String/strchr.c b/MdePkg/Library/LibcLib/String/strchr.c
new file mode 100644
index 000000000000..5e0ce7c43c98
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strchr.c
@@ -0,0 +1,56 @@
+/** @file
+ strchr-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Base.h>
+
+// Very quick notes:
+// We only go through the string once for both functions
+// They are minimal implementations (not speed optimized) of ISO C semantics
+// strchr and strrchr also include the null terminator as part of the string
+// so the code gets a bit clunky to handle that case specifically.
+
+char *
+strchr (
+ const char *Str,
+ int Char
+ )
+{
+ char *S;
+
+ S = (char *)Str;
+
+ for ( ; ; S++) {
+ if (*S == Char) {
+ return S;
+ }
+
+ if (*S == '\0') {
+ return NULL;
+ }
+ }
+}
+
+char *
+strrchr (
+ const char *Str,
+ int Char
+ )
+{
+ char *S, *last;
+
+ S = (char *)Str;
+ last = NULL;
+
+ for ( ; ; S++) {
+ if (*S == Char) {
+ last = S;
+ }
+
+ if (*S == '\0') {
+ return last;
+ }
+ }
+}
diff --git a/MdePkg/Library/LibcLib/String/strcmp.c b/MdePkg/Library/LibcLib/String/strcmp.c
new file mode 100644
index 000000000000..9561fad389d3
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strcmp.c
@@ -0,0 +1,27 @@
+/** @file
+ strcmp-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+
+int
+strcmp (
+ const char *Str1,
+ const char *Str2
+ )
+{
+ return (int)AsciiStrCmp (Str1, Str2);
+}
+
+int
+strncmp (
+ const char *Str1,
+ const char *Str2,
+ size_t Count
+ )
+{
+ return (int)AsciiStrnCmp (Str1, Str2, Count);
+}
diff --git a/MdePkg/Library/LibcLib/String/strcpy.c b/MdePkg/Library/LibcLib/String/strcpy.c
new file mode 100644
index 000000000000..767c18d6a464
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strcpy.c
@@ -0,0 +1,59 @@
+/** @file
+ strcpy-like implementations
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+char *
+strcpy (
+ char *restrict Dest,
+ const char *restrict Source
+ )
+{
+ char *Ret;
+
+ Ret = Dest;
+
+ for ( ; *Source != '\0'; Source++, Dest++) {
+ *Dest = *Source;
+ }
+
+ *Dest = '\0';
+
+ return Ret;
+}
+
+char *
+strncpy (
+ char *restrict Dest,
+ const char *restrict Source,
+ size_t Count
+ )
+{
+ char *Ret;
+
+ Ret = Dest;
+
+ while (Count--) {
+ if (*Source != '\0') {
+ *Dest++ = *Source++;
+ } else {
+ *Dest++ = '\0';
+ }
+ }
+
+ return Ret;
+}
+
+char *
+strcat (
+ char *restrict Dest,
+ const char *restrict Source
+ )
+{
+ return strcpy (Dest + strlen (Dest), Source);
+}
diff --git a/MdePkg/Library/LibcLib/String/strlen.c b/MdePkg/Library/LibcLib/String/strlen.c
new file mode 100644
index 000000000000..a95fb7a18f7b
--- /dev/null
+++ b/MdePkg/Library/LibcLib/String/strlen.c
@@ -0,0 +1,16 @@
+/** @file
+ strlen implementation
+
+ Copyright (c) 2023 Pedro Falcato All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <string.h>
+#include <Library/BaseLib.h>
+
+size_t
+strlen (
+ const char *Str
+ )
+{
+ return AsciiStrLen (Str);
+}
diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc
index 4580481cb580..f17d79286ec4 100644
--- a/MdePkg/MdeLibs.dsc.inc
+++ b/MdePkg/MdeLibs.dsc.inc
@@ -16,3 +16,4 @@
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
SmmCpuRendezvousLib|MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
+ LibcLib|MdePkg/Library/LibcLib/LibcLib.inf
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index e49b2d5b5f28..8c37d89f5418 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -284,6 +284,10 @@
#
ArmTrngLib|Include/Library/ArmTrngLib.h

+ ## @libraryclass Provides various bits of a C standard library.
+ #
+ LibcLib|MdePkg/Library/LibcLib/LibcLib.inf
+
[LibraryClasses.IA32, LibraryClasses.X64, LibraryClasses.AARCH64]
## @libraryclass Provides services to generate random number.
#
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index 32a852dc466e..09828ae12647 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -135,6 +135,7 @@
MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
MdePkg/Library/CcProbeLibNull/CcProbeLibNull.inf
MdePkg/Library/SmmCpuRendezvousLibNull/SmmCpuRendezvousLibNull.inf
+ MdePkg/Library/LibcLib/LibcLib.inf

[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
#
--
2.40.0