#include #include #define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) #define E2BIG -1 #define PAGE_SIZE 4096 struct word_at_a_time { const unsigned long one_bits, high_bits; }; #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } static inline long count_masked_bytes(unsigned long mask) { return mask*0x0001020304050608ul >> 56; } static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) { unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; *bits = mask; return mask; } static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) { return bits; } static inline unsigned long create_zero_mask(unsigned long bits) { bits = (bits - 1) & ~bits; return bits >> 7; } /* The mask we created is directly usable as a bytemask */ #define zero_bytemask(mask) (mask) static inline unsigned long find_zero(unsigned long mask) { return count_masked_bytes(mask); } __attribute__((noinline)) int strscpy_word(char *dest, const char *src, size_t count) { const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; size_t max = count; long res = 0; if (count == 0) return -E2BIG; #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS /* * If src is unaligned, don't cross a page boundary, * since we don't know if the next page is mapped. */ if ((long)src & (sizeof(long) - 1)) { size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1)); if (limit < max) max = limit; } #else /* If src or dest is unaligned, don't do word-at-a-time. */ if (((long) dest | (long) src) & (sizeof(long) - 1)) max = 0; #endif while (max >= sizeof(unsigned long)) { unsigned long c, data; c = *(unsigned long *)(src+res); if (has_zero(c, &data, &constants)) { data = prep_zero_mask(c, data, &constants); data = create_zero_mask(data); *(unsigned long *)(dest+res) = c & zero_bytemask(data); return res + find_zero(data); } *(unsigned long *)(dest+res) = c; res += sizeof(unsigned long); count -= sizeof(unsigned long); max -= sizeof(unsigned long); } while (count) { char c; c = src[res]; dest[res] = c; if (!c) return res; res++; count--; } /* Hit buffer length without finding a NUL; force NUL-termination. */ if (res) dest[res-1] = '\0'; return -E2BIG; } __attribute__((noinline)) int strscpy_byte(char *dest, const char *src, int count) { int res = 0; while (count) { char c; c = src[res]; dest[res] = c; if (!c) return res; res++; count--; } /* Hit buffer length without finding a NUL; force NUL-termination. */ if (res) dest[res-1] = '\0'; return -E2BIG; } char dest[4096] __attribute__((aligned(4096))); char src[4096] __attribute__((aligned(4096))); int main(int argc, char **argv) { unsigned long long i; unsigned long src_len; unsigned long count; if (argc < 4) return -1; src_len = atoi(argv[2]); count = atoi(argv[3]); memset(src, 1, src_len); if (argv[1][0] == 'w') { for (i = 0; i < count; i++) { strscpy_word(dest, src, sizeof(dest)); } } else if (argv[1][0] == 'b') { for (i = 0; i < count; i++) { strscpy_byte(dest, src, sizeof(dest)); } } return 0; }