summaryrefslogtreecommitdiff
path: root/kernel/lib/string.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/lib/string.cpp')
-rw-r--r--kernel/lib/string.cpp78
1 files changed, 78 insertions, 0 deletions
diff --git a/kernel/lib/string.cpp b/kernel/lib/string.cpp
new file mode 100644
index 0000000..3bd60fa
--- /dev/null
+++ b/kernel/lib/string.cpp
@@ -0,0 +1,78 @@
+// ============================================================================
+// lib/string.cpp - Freestanding memory and string operations
+//
+// These are required because we compile with -nostdlib.
+// The compiler may generate implicit calls to memcpy/memset/memmove
+// (e.g., for struct copies, array init), so these must exist with
+// standard C linkage and standard names.
+// ============================================================================
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern "C" {
+
+void* memcpy(void* dest, const void* src, size_t n) {
+ auto* d = static_cast<uint8_t*>(dest);
+ auto* s = static_cast<const uint8_t*>(src);
+ for (size_t i = 0; i < n; i++) d[i] = s[i];
+ return dest;
+}
+
+void* memmove(void* dest, const void* src, size_t n) {
+ auto* d = static_cast<uint8_t*>(dest);
+ auto* s = static_cast<const uint8_t*>(src);
+ if (d < s) {
+ for (size_t i = 0; i < n; i++) d[i] = s[i];
+ } else {
+ for (size_t i = n; i > 0; i--) d[i - 1] = s[i - 1];
+ }
+ return dest;
+}
+
+void* memset(void* dest, int val, size_t n) {
+ auto* d = static_cast<uint8_t*>(dest);
+ for (size_t i = 0; i < n; i++) d[i] = static_cast<uint8_t>(val);
+ return dest;
+}
+
+int memcmp(const void* s1, const void* s2, size_t n) {
+ auto* a = static_cast<const uint8_t*>(s1);
+ auto* b = static_cast<const uint8_t*>(s2);
+ for (size_t i = 0; i < n; i++) {
+ // Cast to int before subtracting: uint8_t → int is safe, range [0, 255]
+ if (a[i] != b[i]) return static_cast<int>(a[i]) - static_cast<int>(b[i]);
+ }
+ return 0;
+}
+
+size_t strlen(const char* s) {
+ size_t len = 0;
+ while (s[len]) len++;
+ return len;
+}
+
+int strcmp(const char* s1, const char* s2) {
+ // Cast to unsigned before comparison — char may be signed,
+ // and unsigned subtraction gives the correct lexicographic ordering.
+ const auto* u1 = reinterpret_cast<const uint8_t*>(s1);
+ const auto* u2 = reinterpret_cast<const uint8_t*>(s2);
+ while (*u1 && *u1 == *u2) { ++u1; ++u2; }
+ return static_cast<int>(*u1) - static_cast<int>(*u2);
+}
+
+char* strcpy(char* dest, const char* src) {
+ char* ret = dest;
+ while (*src) *dest++ = *src++;
+ *dest = '\0';
+ return ret;
+}
+
+char* strncpy(char* dest, const char* src, size_t n) {
+ size_t i = 0;
+ for (; i < n && src[i]; i++) dest[i] = src[i];
+ for (; i < n; i++) dest[i] = '\0';
+ return dest;
+}
+
+} // extern "C"