Coverage Report

Created: 2026-06-08 06:48

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
13.6M
#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
13.3M
{
52
  /* FIXME: Require n > 0? */
53
  /* FIXME: Unroll four times, like memcmp? Probably not worth the
54
     effort. */
55
56
13.3M
  if (n & 1)
57
64.2k
    {
58
64.2k
      n--;
59
64.2k
      dst[n] ^= src[n];
60
64.2k
    }
61
41.0M
  while (n >= 2)
62
27.6M
    {
63
27.6M
      n -= 2;
64
27.6M
      dst[n+1] ^= src[n+1];
65
27.6M
      dst[n] ^= src[n];
66
27.6M
    }
67
13.3M
}
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
118k
{
75
118k
  int shl, shr;
76
118k
  const word_t *src_word;
77
118k
  unsigned offset = ALIGN_OFFSET (src);
78
118k
  word_t s0, s1;
79
80
118k
  assert (n > 0);
81
118k
  shl = CHAR_BIT * offset;
82
118k
  shr = CHAR_BIT * (sizeof(word_t) - offset);
83
84
118k
  src_word = (const word_t *) ((uintptr_t) src & -sizeof(word_t));
85
86
  /* Read top offset bytes, in native byte order. */
87
118k
  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
118k
  if (n & 1)
94
5.92k
    s1 = s0;
95
112k
  else
96
112k
    {
97
112k
      n--;
98
112k
      s1 = src_word[n];
99
112k
      dst[n] ^= MERGE (s1, shl, s0, shr);
100
112k
    }
101
102
118k
  assert (n & 1);
103
329k
  while (n > 2)
104
210k
    {
105
210k
      n -= 2;
106
210k
      s0 = src_word[n+1];
107
210k
      dst[n+1] ^= MERGE(s0, shl, s1, shr);
108
210k
      s1 = src_word[n]; /* FIXME: Overread on last iteration */
109
210k
      dst[n] ^= MERGE(s1, shl, s0, shr);
110
210k
    }
111
118k
  assert (n == 1);
112
  /* Read low wordsize - offset bytes */
113
118k
  READ_PARTIAL (s0, src, sizeof(word_t) - offset);
114
118k
#ifndef WORDS_BIGENDIAN
115
118k
  s0 <<= shl; /* FIXME: eliminate shift? */
116
118k
#endif /* !WORDS_BIGENDIAN */
117
118
118k
  dst[0] ^= MERGE(s0, shl, s1, shr);
119
118k
}
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
13.6M
{
129
13.6M
  unsigned char *dst = dst_in;
130
13.6M
  const unsigned char *src = src_in;
131
132
13.6M
  if (n >= WORD_T_THRESH)
133
13.5M
    {
134
13.5M
      unsigned i;
135
13.5M
      unsigned offset;
136
13.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
16.2M
      for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
140
2.71M
  {
141
2.71M
    n--;
142
2.71M
    dst[n] ^= src[n];
143
2.71M
  }
144
13.5M
      offset = ALIGN_OFFSET(src + n);
145
13.5M
      nwords = n / sizeof (word_t);
146
13.5M
      n %= sizeof (word_t);
147
148
13.5M
      if (offset)
149
118k
  memxor_different_alignment ((word_t *) (dst+n), src+n, nwords);
150
13.3M
      else
151
13.3M
  memxor_common_alignment ((word_t *) (dst+n),
152
13.3M
         (const word_t *) (src+n), nwords);
153
13.5M
    }
154
13.9M
  while (n > 0)
155
359k
    {
156
359k
      n--;
157
359k
      dst[n] ^= src[n];
158
359k
    }
159
160
13.6M
  return dst;
161
13.6M
}