Coverage Report

Created: 2024-11-25 06:31

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