public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [RFC PATCH 1/1] MdePkg: Add a libc implementation
@ 2023-03-31  2:30 Pedro Falcato
  2023-03-31 11:55 ` [edk2-devel] " Gerd Hoffmann
  2023-04-06  3:07 ` Michael D Kinney
  0 siblings, 2 replies; 3+ messages in thread
From: Pedro Falcato @ 2023-03-31  2:30 UTC (permalink / raw)
  To: devel; +Cc: Pedro Falcato, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Benny Lin

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Benny Lin <benny.lin@intel.com>
Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
 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


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [edk2-devel] [RFC PATCH 1/1] MdePkg: Add a libc implementation
  2023-03-31  2:30 [RFC PATCH 1/1] MdePkg: Add a libc implementation Pedro Falcato
@ 2023-03-31 11:55 ` Gerd Hoffmann
  2023-04-06  3:07 ` Michael D Kinney
  1 sibling, 0 replies; 3+ messages in thread
From: Gerd Hoffmann @ 2023-03-31 11:55 UTC (permalink / raw)
  To: devel, pedro.falcato
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Benny Lin

  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


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH 1/1] MdePkg: Add a libc implementation
  2023-03-31  2:30 [RFC PATCH 1/1] MdePkg: Add a libc implementation Pedro Falcato
  2023-03-31 11:55 ` [edk2-devel] " Gerd Hoffmann
@ 2023-04-06  3:07 ` Michael D Kinney
  1 sibling, 0 replies; 3+ messages in thread
From: Michael D Kinney @ 2023-04-06  3:07 UTC (permalink / raw)
  To: Pedro Falcato, devel@edk2.groups.io
  Cc: Gao, Liming, Liu, Zhiguang, Lin, Benny, Kinney, Michael D

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@gmail.com>
> Sent: Thursday, March 30, 2023 7:31 PM
> To: devel@edk2.groups.io
> Cc: Pedro Falcato <pedro.falcato@gmail.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming
> <gaoliming@byosoft.com.cn>; Liu, Zhiguang <zhiguang.liu@intel.com>; Lin, Benny <benny.lin@intel.com>
> 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@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Benny Lin <benny.lin@intel.com>
> Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
> ---
>  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


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-04-06  3:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-31  2:30 [RFC PATCH 1/1] MdePkg: Add a libc implementation Pedro Falcato
2023-03-31 11:55 ` [edk2-devel] " Gerd Hoffmann
2023-04-06  3:07 ` Michael D Kinney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox