Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions libs/libc/libc.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@

#define UNALIGNED(x, y) ((UNALIGNED_X(x)) | (UNALIGNED_X(y)))

/* Nonzero if x and y disagree about where a "libc_data_t" boundary falls.
* A pair that agrees can be walked up to the boundary a byte at a time and
* handled a word at a time from there, since aligning one aligns the
* other. A pair that disagrees cannot, because no single boundary serves
* both.
*/

#define MISALIGNED(x, y) \
((((uintptr_t)(x)) ^ ((uintptr_t)(y))) & (sizeof(libc_data_t) - 1))

#define ALIGNED(x) \
(((libc_data_t)(uintptr_t)(x) & (sizeof(libc_data_t) - 1)) == 0)

Expand Down
21 changes: 21 additions & 0 deletions libs/libc/string/lib_bsdmemccpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@ FAR void *memccpy(FAR void *s1, FAR const void *s2, int c, size_t n)
FAR const unsigned char *pin = (FAR const unsigned char *)s2;
unsigned char endchar = c & 0xff;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The end character is left for the byte loop, which copies it
* and reports where it landed. Fewer than LITTLEBLOCKSIZE bytes are
* copied and the size was tested against that first, so this cannot run
* past the end.
*/

if (!TOO_SMALL(n) && !MISALIGNED(pin, pout) && UNALIGNED_X(pin))
{
while (*pin != endchar)
{
*pout++ = *pin++;
n--;
if (!UNALIGNED_X(pin))
{
break;
}
}
}

/* If the size is small, or either pin or pout is unaligned,
* then punt into the byte copy loop. This should be rare.
*/
Expand Down
22 changes: 22 additions & 0 deletions libs/libc/string/lib_bsdmemcmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@ int memcmp(FAR const void *s1, FAR const void *s2, size_t n)
FAR unsigned char *p1 = (FAR unsigned char *)s1;
FAR unsigned char *p2 = (FAR unsigned char *)s2;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. A difference found on the way stops the walk and is reported
* by the byte loop. Fewer than LITTLEBLOCKSIZE bytes are compared and
* the size was tested against that first, so this cannot run past the
* end.
*/

if (!TOO_SMALL(n) && !MISALIGNED(p1, p2) && UNALIGNED_X(p1))
{
while (*p1 == *p2)
{
p1++;
p2++;
n--;
if (!UNALIGNED_X(p1))
{
break;
}
}
}

/* If the size is too small, or either pointer is unaligned,
* then we punt to the byte compare loop. Hopefully this will
* not turn up in inner loops.
Expand Down
16 changes: 16 additions & 0 deletions libs/libc/string/lib_bsdmemcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ FAR void *memcpy(FAR void *dest, FAR const void *src, size_t n)
FAR char *pout = dest;
FAR const char *pin = src;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. Fewer than LITTLEBLOCKSIZE bytes are copied and the size was
* tested against that first, so this cannot run past the end.
*/

if (!TOO_SMALL(n) && !MISALIGNED(pin, pout) && UNALIGNED_X(pin))
{
do
{
*pout++ = *pin++;
n--;
}
while (UNALIGNED_X(pin));
}

/* If the size is small, or either pin or pout is unaligned,
* then punt into the byte copy loop. This should be rare.
*/
Expand Down
17 changes: 17 additions & 0 deletions libs/libc/string/lib_bsdstpcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ no_builtin("stpcpy")
nosanitize_address
FAR char *stpcpy(FAR char *dest, FAR const char *src)
{
/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The terminator is left for the byte loop to copy.
*/

if (!MISALIGNED(src, dest) && UNALIGNED_X(src))
{
while (*src != '\0')
{
*dest++ = *src++;
if (!UNALIGNED_X(src))
{
break;
}
}
}

/* If src or dest is unaligned, then copy bytes. */

if (!UNALIGNED(src, dest))
Expand Down
20 changes: 20 additions & 0 deletions libs/libc/string/lib_bsdstpncpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ FAR char *stpncpy(FAR char *dest, FAR const char *src, size_t n)
{
FAR char *ret = NULL;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The terminator is left for the byte loop, which also pads.
* Fewer than LITTLEBLOCKSIZE bytes are copied and n was tested against
* that first, so n cannot run out here.
*/

if (!MISALIGNED(src, dest) && !TOO_SMALL(n) && UNALIGNED_X(src))
{
while (*src != '\0')
{
*dest++ = *src++;
n--;
if (!UNALIGNED_X(src))
{
break;
}
}
}

/* If src and dest is aligned and n large enough, then copy words. */

if (!UNALIGNED(src, dest) && !TOO_SMALL(n))
Expand Down
19 changes: 19 additions & 0 deletions libs/libc/string/lib_bsdstrcmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ no_builtin("strcmp")
nosanitize_address
int strcmp(FAR const char *cs, FAR const char *ct)
{
/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. A difference or a terminator found on the way stops the walk
* and is reported by the byte loop.
*/

if (!MISALIGNED(cs, ct) && UNALIGNED_X(cs))
{
while (*cs != '\0' && *cs == *ct)
{
cs++;
ct++;
if (!UNALIGNED_X(cs))
{
break;
}
}
}

/* If cs or ct are unaligned, then compare bytes. */

if (!UNALIGNED(cs, ct))
Expand Down
17 changes: 17 additions & 0 deletions libs/libc/string/lib_bsdstrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ FAR char *strcpy(FAR char *dest, FAR const char *src)
FAR char *dst0 = dest;
FAR const char *src0 = src;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The terminator is left for the byte loop to copy.
*/

if (!MISALIGNED(src0, dst0) && UNALIGNED_X(src0))
{
while (*src0 != '\0')
{
*dst0++ = *src0++;
if (!UNALIGNED_X(src0))
{
break;
}
}
}

/* If SRC or DEST is unaligned, then copy bytes. */

if (!UNALIGNED(src0, dst0))
Expand Down
25 changes: 25 additions & 0 deletions libs/libc/string/lib_bsdstrncmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ int strncmp(FAR const char *cs, FAR const char *ct, size_t nb)
return 0;
}

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. A difference found on the way stops the walk and is reported
* by the byte loop; the count running out or a terminator means the
* strings are equal over the whole comparison.
*/

if (!MISALIGNED(cs, ct) && UNALIGNED_X(cs))
{
while (*cs == *ct)
{
if (--nb == 0 || *cs == '\0')
{
return 0;
}

cs++;
ct++;
if (!UNALIGNED_X(cs))
{
break;
}
}
}

/* If cs or ct are unaligned, then compare bytes. */

if (!UNALIGNED(cs, ct))
Expand Down
20 changes: 20 additions & 0 deletions libs/libc/string/lib_bsdstrncpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ FAR char *strncpy(FAR char *dest, FAR const char *src, size_t n)
FAR char *dst0 = dest;
FAR const char *src0 = src;

/* Walk a pair that agrees about where a boundary falls up to it, so that
* the word path below is reached even when the caller aligned neither
* pointer. The terminator is left for the byte loop, which also pads.
* Fewer than LITTLEBLOCKSIZE bytes are copied and n was tested against
* that first, so n cannot run out here.
*/

if (!MISALIGNED(src0, dst0) && !TOO_SMALL(n) && UNALIGNED_X(src0))
{
while (*src0 != '\0')
{
*dst0++ = *src0++;
n--;
if (!UNALIGNED_X(src0))
{
break;
}
}
}

/* If src and dest is aligned and n large enough, then copy words. */

if (!UNALIGNED(src0, dst0) && !TOO_SMALL(n))
Expand Down
Loading