Coverage Report

Created: 2026-09-28 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nettle/memxor.c
Line
Count
Source
1
/* memxor.c
2
3
   Copyright (C) 2010, 2014 Niels Möller
4
5
   This file is part of GNU Nettle.
6
7
   GNU Nettle is free software: you can redistribute it and/or
8
   modify it under the terms of either:
9
10
     * the GNU Lesser General Public License as published by the Free
11
       Software Foundation; either version 3 of the License, or (at your
12
       option) any later version.
13
14
   or
15
16
     * the GNU General Public License as published by the Free
17
       Software Foundation; either version 2 of the License, or (at your
18
       option) any later version.
19
20
   or both in parallel, as here.
21
22
   GNU Nettle is distributed in the hope that it will be useful,
23
   but WITHOUT ANY WARRANTY; without even the implied warranty of
24
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
   General Public License for more details.
26
27
   You should have received copies of the GNU General Public License and
28
   the GNU Lesser General Public License along with this program.  If
29
   not, see http://www.gnu.org/licenses/.
30
*/
31
32
/* Implementation inspired by memcmp in glibc, contributed to the FSF
33
   by Torbjorn Granlund.
34
 */
35
36
#if HAVE_CONFIG_H
37
# include "config.h"
38
#endif
39
40
#include <assert.h>
41
#include <limits.h>
42
43
#include "memxor.h"
44
#include "memxor-internal.h"
45
46
11.5M
#define WORD_T_THRESH 16
47
48
/* XOR word-aligned areas. n is the number of words, not bytes. */
49
static void
50
memxor_common_alignment (word_t *dst, const word_t *src, size_t n)
51
11.5M
{
52
  /* FIXME: Require n > 0? */
53
  /* FIXME: Unroll four times, like memcmp? Probably not worth the
54
     effort. */
55
56
11.5M
  if (n & 1)
57
40.2k
    {
58
40.2k
      n--;
59
40.2k
      dst[n] ^= src[n];
60
40.2k
    }
61
35.6M
  while (n >= 2)
62
24.1M
    {
63
24.1M
      n -= 2;
64
24.1M
      dst[n+1] ^= src[n+1];
65
24.1M
      dst[n] ^= src[n];
66
24.1M
    }
67
11.5M
}
68
69
/* XOR *un-aligned* src-area onto aligned dst area. n is number of
70
   words, not bytes. Assumes we can read complete words at the start
71
   and end of the src operand. */
72
static void
73
memxor_different_alignment (word_t *dst, const unsigned char *src, size_t n)
74
59.9k
{
75
59.9k
  int shl, shr;
76
59.9k
  const word_t *src_word;
77
59.9k
  unsigned offset = ALIGN_OFFSET (src);
78
59.9k
  word_t s0, s1;
79
80
59.9k
  assert (n > 0);
81
59.9k
  shl = CHAR_BIT * offset;
82
59.9k
  shr = CHAR_BIT * (sizeof(word_t) - offset);
83
84
59.9k
  src_word = (const word_t *) ((uintptr_t) src & -sizeof(word_t));
85
86
  /* Read top offset bytes, in native byte order. */
87
59.9k
  READ_PARTIAL (s0, (unsigned char *) &src_word[n], offset);
88
#ifdef WORDS_BIGENDIAN
89
  s0 <<= shr; /* FIXME: Eliminate this shift? */
90
#endif
91
92
  /* Do n-1 regular iterations */
93
59.9k
  if (n & 1)
94
5.44k
    s1 = s0;
95
54.4k
  else
96
54.4k
    {
97
54.4k
      n--;
98
54.4k
      s1 = src_word[n];
99
54.4k
      dst[n] ^= MERGE (s1, shl, s0, shr);
100
54.4k
    }
101
102
59.9k
  assert (n & 1);
103
196k
  while (n > 2)
104
136k
    {
105
136k
      n -= 2;
106
136k
      s0 = src_word[n+1];
107
136k
      dst[n+1] ^= MERGE(s0, shl, s1, shr);
108
136k
      s1 = src_word[n]; /* FIXME: Overread on last iteration */
109
136k
      dst[n] ^= MERGE(s1, shl, s0, shr);
110
136k
    }
111
59.9k
  assert (n == 1);
112
  /* Read low wordsize - offset bytes */
113
59.9k
  READ_PARTIAL (s0, src, sizeof(word_t) - offset);
114
59.9k
#ifndef WORDS_BIGENDIAN
115
59.9k
  s0 <<= shl; /* FIXME: eliminate shift? */
116
59.9k
#endif /* !WORDS_BIGENDIAN */
117
118
59.9k
  dst[0] ^= MERGE(s0, shl, s1, shr);
119
59.9k
}
120
121
/* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45
122
   cycles/byte unaligned. */
123
124
/* XOR LEN bytes starting at SRCADDR onto DESTADDR. Result undefined
125
   if the source overlaps with the destination. Return DESTADDR. */
126
void *
127
memxor(void *dst_in, const void *src_in, size_t n)
128
11.5M
{
129
11.5M
  unsigned char *dst = dst_in;
130
11.5M
  const unsigned char *src = src_in;
131
132
11.5M
  if (n >= WORD_T_THRESH)
133
11.5M
    {
134
11.5M
      unsigned i;
135
11.5M
      unsigned offset;
136
11.5M
      size_t nwords;
137
      /* There are at least some bytes to compare.  No need to test
138
   for N == 0 in this alignment loop.  */
139
14.3M
      for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
140
2.73M
  {
141
2.73M
    n--;
142
2.73M
    dst[n] ^= src[n];
143
2.73M
  }
144
11.5M
      offset = ALIGN_OFFSET(src + n);
145
11.5M
      nwords = n / sizeof (word_t);
146
11.5M
      n %= sizeof (word_t);
147
148
11.5M
      if (offset)
149
59.9k
  memxor_different_alignment ((word_t *) (dst+n), src+n, nwords);
150
11.5M
      else
151
11.5M
  memxor_common_alignment ((word_t *) (dst+n),
152
11.5M
         (const word_t *) (src+n), nwords);
153
11.5M
    }
154
11.7M
  while (n > 0)
155
163k
    {
156
163k
      n--;
157
163k
      dst[n] ^= src[n];
158
163k
    }
159
160
11.5M
  return dst;
161
11.5M
}