boot: Add memcmp/memcpy/memset

This commit is contained in:
Jan Janssen
2022-05-31 15:14:56 +02:00
parent 60c2af56d6
commit f7967716e3
3 changed files with 127 additions and 1 deletions
+59 -1
View File
@@ -4,7 +4,6 @@
#include <stdint.h>
#include "efi-string.h"
#include "macro-fundamental.h"
/* String functions for both char and char16_t that should behave the same way as their respective
* counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas
@@ -138,3 +137,62 @@ DEFINE_STRCPY(char16_t, strcpy16);
DEFINE_STRCHR(char, strchr8);
DEFINE_STRCHR(char16_t, strchr16);
int efi_memcmp(const void *p1, const void *p2, size_t n) {
if (!p1 || !p2)
return CMP(p1, p2);
const uint8_t *up1 = p1, *up2 = p2;
while (n > 0) {
if (*up1 != *up2)
return *up1 - *up2;
up1++;
up2++;
n--;
}
return 0;
}
void *efi_memcpy(void * restrict dest, const void * restrict src, size_t n) {
if (!dest || !src || n == 0)
return dest;
uint8_t *d = dest;
const uint8_t *s = src;
while (n > 0) {
*d = *s;
d++;
s++;
n--;
}
return dest;
}
void *efi_memset(void *p, int c, size_t n) {
if (!p || n == 0)
return p;
uint8_t *q = p;
while (n > 0) {
*q = c;
q++;
n--;
}
return p;
}
#ifdef SD_BOOT
# undef memcmp
# undef memcpy
# undef memset
/* Provide the actual implementation for the builtins. To prevent a linker error, we mark memcpy/memset as
* weak, because gnu-efi is currently providing them. */
__attribute__((alias("efi_memcmp"))) int memcmp(const void *p1, const void *p2, size_t n);
__attribute__((weak, alias("efi_memcpy"))) void *memcpy(void * restrict dest, const void * restrict src, size_t n);
__attribute__((weak, alias("efi_memset"))) void *memset(void *p, int c, size_t n);
#endif
+17
View File
@@ -5,6 +5,8 @@
#include <stddef.h>
#include <uchar.h>
#include "macro-fundamental.h"
size_t strnlen8(const char *s, size_t n);
size_t strnlen16(const char16_t *s, size_t n);
@@ -71,3 +73,18 @@ char16_t *strcpy16(char16_t * restrict dest, const char16_t * restrict src);
char *strchr8(const char *s, char c);
char16_t *strchr16(const char16_t *s, char16_t c);
#ifdef SD_BOOT
/* The compiler normaly has knowledge about standard functions such as memcmp, but this is not the case when
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
* inline its own implementation and instead issue a library call. */
# define memcmp __builtin_memcmp
# define memcpy __builtin_memcpy
# define memset __builtin_memset
#endif
/* The actual implementations of builtins with efi_ prefix so we can unit test them. */
int efi_memcmp(const void *p1, const void *p2, size_t n);
void *efi_memcpy(void * restrict dest, const void * restrict src, size_t n);
void *efi_memset(void *p, int c, size_t n);
+51
View File
@@ -240,4 +240,55 @@ TEST(strchr16) {
assert_se(strchr16(str, 'B') == &str[4]);
}
TEST(efi_memcmp) {
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
assert_se(efi_memcmp(NULL, NULL, 1) == 0);
assert_se(efi_memcmp(NULL, "", 1) < 0);
assert_se(efi_memcmp("", NULL, 1) > 0);
assert_se(efi_memcmp("", "", 0) == 0);
assert_se(efi_memcmp("", "", 1) == 0);
assert_se(efi_memcmp("1", "1", 1) == 0);
assert_se(efi_memcmp("1", "2", 1) < 0);
assert_se(efi_memcmp("A", "a", 1) < 0);
assert_se(efi_memcmp("a", "A", 1) > 0);
assert_se(efi_memcmp("abc", "ab", 2) == 0);
assert_se(efi_memcmp("ab", "abc", 3) < 0);
assert_se(efi_memcmp("ab\000bd", "ab\000bd", 6) == 0);
assert_se(efi_memcmp("ab\000b\0", "ab\000bd", 6) < 0);
}
TEST(efi_memcpy) {
char buf[10];
assert_se(!efi_memcpy(NULL, NULL, 0));
assert_se(!efi_memcpy(NULL, "", 1));
assert_se(efi_memcpy(buf, NULL, 0) == buf);
assert_se(efi_memcpy(buf, NULL, 1) == buf);
assert_se(efi_memcpy(buf, "a", 0) == buf);
assert_se(efi_memcpy(buf, "", 1) == buf);
assert_se(memcmp(buf, "", 1) == 0);
assert_se(efi_memcpy(buf, "1", 1) == buf);
assert_se(memcmp(buf, "1", 1) == 0);
assert_se(efi_memcpy(buf, "23", 3) == buf);
assert_se(memcmp(buf, "23", 3) == 0);
assert_se(efi_memcpy(buf, "45\0ab\0\0\0c", 9) == buf);
assert_se(memcmp(buf, "45\0ab\0\0\0c", 9) == 0);
}
TEST(efi_memset) {
char buf[10];
assert_se(!efi_memset(NULL, '1', 0));
assert_se(!efi_memset(NULL, '1', 1));
assert_se(efi_memset(buf, '1', 0) == buf);
assert_se(efi_memset(buf, '2', 1) == buf);
assert_se(memcmp(buf, "2", 1) == 0);
assert_se(efi_memset(buf, '4', 4) == buf);
assert_se(memcmp(buf, "4444", 4) == 0);
assert_se(efi_memset(buf, 'a', 10) == buf);
assert_se(memcmp(buf, "aaaaaaaaaa", 10) == 0);
}
DEFINE_TEST_MAIN(LOG_INFO);