Update copyright notices with scripts/update-copyrights
[glibc.git] / sysdeps / x86_64 / strcpy_chk.S
blob986339e6b4b5f05ada933341f8918a084d9918d3
1 /* strcpy/stpcpy checking implementation for x86-64.
2    Copyright (C) 2002-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Andreas Jaeger <aj@suse.de>, 2002.
5    Adopted into checking version by Jakub Jelinek <jakub@redhat.com>.
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
21 #include <sysdep.h>
22 #include "asm-syntax.h"
24 #ifndef USE_AS_STPCPY_CHK
25 # define STRCPY_CHK __strcpy_chk
26 #endif
28         .text
29 ENTRY (STRCPY_CHK)
30         movq    %rsi, %rcx      /* Source register. */
31         andl    $7, %ecx        /* mask alignment bits */
32 #ifndef USE_AS_STPCPY_CHK
33         movq    %rdi, %r10      /* Duplicate destination pointer.  */
34 #endif
35         jz 5f                   /* aligned => start loop */
37         cmpq    $8, %rdx        /* Check if only few bytes left in
38                                    destination.  */
39         jb      50f
41         subq    $8, %rcx        /* We need to align to 8 bytes.  */
42         addq    %rcx, %rdx      /* Subtract count of stored bytes
43                                    in the cycle below from destlen.  */
45         /* Search the first bytes directly.  */
47         movb    (%rsi), %al     /* Fetch a byte */
48         testb   %al, %al        /* Is it NUL? */
49         movb    %al, (%rdi)     /* Store it */
50         jz      4f              /* If it was NUL, done! */
51         incq    %rsi
52         incq    %rdi
53         incl    %ecx
54         jnz     0b
57         movq $0xfefefefefefefeff,%r8
58         cmpq    $32, %rdx       /* Are there enough bytes in destination
59                                    for the next unrolled round?  */
60         jb      60f             /* If not, avoid the unrolled loop.  */
62         /* Now the sources is aligned.  Unfortunatly we cannot force
63            to have both source and destination aligned, so ignore the
64            alignment of the destination.  */
65         .p2align 4
67         /* 1st unroll.  */
68         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
69         addq    $8, %rsi        /* Adjust pointer for next word.  */
70         movq    %rax, %r9       /* Save a copy for NUL finding.  */
71         addq    %r8, %r9        /* add the magic value to the word.  We get
72                                    carry bits reported for each byte which
73                                    is *not* 0 */
74         jnc     3f              /* highest byte is NUL => return pointer */
75         xorq    %rax, %r9       /* (word+magic)^word */
76         orq     %r8, %r9        /* set all non-carry bits */
77         incq    %r9             /* add 1: if one carry bit was *not* set
78                                    the addition will not result in 0.  */
80         jnz     3f              /* found NUL => return pointer */
82         movq    %rax, (%rdi)    /* Write value to destination.  */
83         addq    $8, %rdi        /* Adjust pointer.  */
85         /* 2nd unroll.  */
86         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
87         addq    $8, %rsi        /* Adjust pointer for next word.  */
88         movq    %rax, %r9       /* Save a copy for NUL finding.  */
89         addq    %r8, %r9        /* add the magic value to the word.  We get
90                                    carry bits reported for each byte which
91                                    is *not* 0 */
92         jnc     3f              /* highest byte is NUL => return pointer */
93         xorq    %rax, %r9       /* (word+magic)^word */
94         orq     %r8, %r9        /* set all non-carry bits */
95         incq    %r9             /* add 1: if one carry bit was *not* set
96                                    the addition will not result in 0.  */
98         jnz     3f              /* found NUL => return pointer */
100         movq    %rax, (%rdi)    /* Write value to destination.  */
101         addq    $8, %rdi        /* Adjust pointer.  */
103         /* 3rd unroll.  */
104         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
105         addq    $8, %rsi        /* Adjust pointer for next word.  */
106         movq    %rax, %r9       /* Save a copy for NUL finding.  */
107         addq    %r8, %r9        /* add the magic value to the word.  We get
108                                    carry bits reported for each byte which
109                                    is *not* 0 */
110         jnc     3f              /* highest byte is NUL => return pointer */
111         xorq    %rax, %r9       /* (word+magic)^word */
112         orq     %r8, %r9        /* set all non-carry bits */
113         incq    %r9             /* add 1: if one carry bit was *not* set
114                                    the addition will not result in 0.  */
116         jnz     3f              /* found NUL => return pointer */
118         movq    %rax, (%rdi)    /* Write value to destination.  */
119         addq    $8, %rdi        /* Adjust pointer.  */
121         /* 4th unroll.  */
122         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
123         addq    $8, %rsi        /* Adjust pointer for next word.  */
124         movq    %rax, %r9       /* Save a copy for NUL finding.  */
125         addq    %r8, %r9        /* add the magic value to the word.  We get
126                                    carry bits reported for each byte which
127                                    is *not* 0 */
128         jnc     3f              /* highest byte is NUL => return pointer */
129         xorq    %rax, %r9       /* (word+magic)^word */
130         orq     %r8, %r9        /* set all non-carry bits */
131         incq    %r9             /* add 1: if one carry bit was *not* set
132                                    the addition will not result in 0.  */
134         jnz     3f              /* found NUL => return pointer */
136         subq    $32, %rdx       /* Adjust destlen.  */
137         movq    %rax, (%rdi)    /* Write value to destination.  */
138         addq    $8, %rdi        /* Adjust pointer.  */
139         cmpq    $32, %rdx       /* Are there enough bytes in destination
140                                    for the next unrolled round?  */
141         jae     1b              /* Next iteration.  */
144         cmpq    $8, %rdx        /* Are there enough bytes in destination
145                                    for the next unrolled round?  */
146         jb      50f             /* Now, copy and check byte by byte.  */
148         movq    (%rsi), %rax    /* Read double word (8 bytes).  */
149         addq    $8, %rsi        /* Adjust pointer for next word.  */
150         movq    %rax, %r9       /* Save a copy for NUL finding.  */
151         addq    %r8, %r9        /* add the magic value to the word.  We get
152                                    carry bits reported for each byte which
153                                    is *not* 0 */
154         jnc     3f              /* highest byte is NUL => return pointer */
155         xorq    %rax, %r9       /* (word+magic)^word */
156         orq     %r8, %r9        /* set all non-carry bits */
157         incq    %r9             /* add 1: if one carry bit was *not* set
158                                    the addition will not result in 0.  */
160         jnz     3f              /* found NUL => return pointer */
162         subq    $8, %rdx        /* Adjust destlen.  */
163         movq    %rax, (%rdi)    /* Write value to destination.  */
164         addq    $8, %rdi        /* Adjust pointer.  */
165         jmp     60b             /* Next iteration.  */
167         /* Do the last few bytes. %rax contains the value to write.
168            The loop is unrolled twice.  */
169         .p2align 4
171         /* Note that stpcpy needs to return with the value of the NUL
172            byte.  */
173         movb    %al, (%rdi)     /* 1st byte.  */
174         testb   %al, %al        /* Is it NUL.  */
175         jz      4f              /* yes, finish.  */
176         incq    %rdi            /* Increment destination.  */
177         movb    %ah, (%rdi)     /* 2nd byte.  */
178         testb   %ah, %ah        /* Is it NUL?.  */
179         jz      4f              /* yes, finish.  */
180         incq    %rdi            /* Increment destination.  */
181         shrq    $16, %rax       /* Shift...  */
182         jmp     3b              /* and look at next two bytes in %rax.  */
185         /* Search the bytes directly, checking for overflows.  */
186         incq    %rsi
187         incq    %rdi
188         decq    %rdx
189         jz      HIDDEN_JUMPTARGET (__chk_fail)
191         movb    (%rsi), %al     /* Fetch a byte */
192         testb   %al, %al        /* Is it NUL? */
193         movb    %al, (%rdi)     /* Store it */
194         jnz     51b             /* If it was NUL, done! */
196 #ifdef USE_AS_STPCPY_CHK
197         movq    %rdi, %rax      /* Destination is return value.  */
198 #else
199         movq    %r10, %rax      /* Source is return value.  */
200 #endif
201         retq
204         testq   %rdx, %rdx
205         jnz     52b
206         jmp     HIDDEN_JUMPTARGET (__chk_fail)
208 END (STRCPY_CHK)