drd: Add a consistency check
[valgrind.git] / coregrind / m_trampoline.S
blob3d2be09ba762c61d060f836a8b53904bda487e1f
2 /*--------------------------------------------------------------------*/
3 /*--- Trampoline code page stuff.                   m_trampoline.S ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
10   Copyright (C) 2000-2013 Julian Seward 
11      jseward@acm.org
12   Copyright (C) 2006-2013 OpenWorks LLP
13      info@open-works.co.uk
14         
15   This program is free software; you can redistribute it and/or
16   modify it under the terms of the GNU General Public License as
17   published by the Free Software Foundation; either version 2 of the
18   License, or (at your option) any later version.
20   This program is distributed in the hope that it will be useful, but
21   WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   General Public License for more details.
25   You should have received a copy of the GNU General Public License
26   along with this program; if not, write to the Free Software
27   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28   02111-1307, USA.
30   The GNU General Public License is contained in the file COPYING.
33 #include "pub_core_basics_asm.h"
34 #include "pub_core_vkiscnums_asm.h"
36 /* ------------------ SIMULATED CPU HELPERS ------------------ */
37 /* 
38    Replacements for some functions to do with vsyscalls and signals.
39    This code runs on the simulated CPU.
41         
42 /*---------------------- x86-linux ----------------------*/
43 #if defined(VGP_x86_linux)
45 #       define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
46 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
47 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
48 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
49 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
51         /* a leading page of unexecutable code */
52         UD2_PAGE
54 .global VG_(trampoline_stuff_start)
55 VG_(trampoline_stuff_start):
57 .global VG_(x86_linux_SUBST_FOR_sigreturn)
58 VG_(x86_linux_SUBST_FOR_sigreturn):
59         /* This is a very specific sequence which GDB uses to
60            recognize signal handler frames.  Also gcc: see
61            x86_fallback_frame_state() in
62            gcc-4.1.0/gcc/config/i386/linux-unwind.h */
63         popl    %eax
64         movl    $ __NR_sigreturn, %eax
65         int     $0x80
66         ud2
68 .global VG_(x86_linux_SUBST_FOR_rt_sigreturn)
69 VG_(x86_linux_SUBST_FOR_rt_sigreturn):
70         /* Likewise for rt signal frames */
71         movl    $ __NR_rt_sigreturn, %eax
72         int     $0x80
73         ud2
75 /* There's no particular reason that this needs to be handwritten
76    assembly, but since that's what this file contains, here's a
77    simple index implementation (written in C and compiled by gcc.)
79    unsigned char* REDIR_FOR_index ( const char* s, int c ) 
80    { 
81       unsigned char  ch = (unsigned char)((unsigned int)c); 
82       unsigned char* p  = (unsigned char*)s; 
83       while (1) { 
84          if (*p == ch) return p;
85          if (*p == 0)  return 0; 
86          p++; 
87       } 
88    }
90 .global VG_(x86_linux_REDIR_FOR_index)
91 .type   VG_(x86_linux_REDIR_FOR_index), @function
92 VG_(x86_linux_REDIR_FOR_index):
93         pushl   %ebp
94         movl    %esp, %ebp
95         movl    8(%ebp), %eax
96         movzbl  12(%ebp), %ecx
97         movzbl  (%eax), %edx
98         cmpb    %dl, %cl
99         jne     .L9
100         jmp     .L2
101 .L11:
102         addl    $1, %eax
103         movzbl  (%eax), %edx
104         cmpb    %dl, %cl
105         je      .L2
106 .L9:
107         testb   %dl, %dl
108         jne     .L11
109         xorl    %eax, %eax
110 .L2:
111         popl    %ebp
112         ret
113 .size VG_(x86_linux_REDIR_FOR_index), .-VG_(x86_linux_REDIR_FOR_index)
115 /* There's no particular reason that this needs to be handwritten
116    assembly, but since that's what this file contains, here's a
117    simple strlen implementation (written in C and compiled by gcc.)
119 .global VG_(x86_linux_REDIR_FOR_strlen)
120 .type   VG_(x86_linux_REDIR_FOR_strlen), @function
121 VG_(x86_linux_REDIR_FOR_strlen):
122         pushl   %ebp
123         movl    %esp, %ebp
124         movl    8(%ebp), %edx
125         movl    %edx, %eax
126         jmp     2f
127 1:      incl    %eax
128 2:      cmpb    $0, (%eax)
129         jne     1b
130         subl    %edx, %eax
131         popl    %ebp
132         ret
133 .size VG_(x86_linux_REDIR_FOR_strlen), .-VG_(x86_linux_REDIR_FOR_strlen)
136 .global VG_(trampoline_stuff_end)
137 VG_(trampoline_stuff_end):
139         /* and a trailing page of unexecutable code */
140         UD2_PAGE
142 #       undef UD2_16
143 #       undef UD2_64
144 #       undef UD2_256
145 #       undef UD2_1024
146 #       undef UD2_PAGE
147         
148 /*---------------------- amd64-linux ----------------------*/
149 #else
150 #if defined(VGP_amd64_linux)
152 #       define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
153 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
154 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
155 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
156 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
158         /* a leading page of unexecutable code */
159         UD2_PAGE
161 .global VG_(trampoline_stuff_start)
162 VG_(trampoline_stuff_start):
164 .global VG_(amd64_linux_SUBST_FOR_rt_sigreturn)
165 VG_(amd64_linux_SUBST_FOR_rt_sigreturn):
166         /* This is a very specific sequence which GDB uses to
167            recognize signal handler frames. */
168         movq    $__NR_rt_sigreturn, %rax
169         syscall
170         ud2
172 .global VG_(amd64_linux_REDIR_FOR_vgettimeofday)
173 .type   VG_(amd64_linux_REDIR_FOR_vgettimeofday), @function
174 VG_(amd64_linux_REDIR_FOR_vgettimeofday):
175 .LfnB2:
176         movq    $__NR_gettimeofday, %rax
177         syscall
178         ret
179 .LfnE2:
180 .size VG_(amd64_linux_REDIR_FOR_vgettimeofday), .-.LfnB2
181         
182 .global VG_(amd64_linux_REDIR_FOR_vtime)
183 .type   VG_(amd64_linux_REDIR_FOR_vtime), @function
184 VG_(amd64_linux_REDIR_FOR_vtime):
185 .LfnB3: 
186         movq    $__NR_time, %rax
187         syscall
188         ret
189 .LfnE3:
190 .size VG_(amd64_linux_REDIR_FOR_vtime), .-.LfnB3
192 .global VG_(amd64_linux_REDIR_FOR_vgetcpu)
193 .type   VG_(amd64_linux_REDIR_FOR_vgetcpu), @function
194 VG_(amd64_linux_REDIR_FOR_vgetcpu):
195 .LfnB4:
196         movq    $__NR_getcpu, %rax
197         syscall
198         ret
199 .LfnE4:
200 .size VG_(amd64_linux_REDIR_FOR_vgetcpu), .-.LfnB4
202 /* There's no particular reason that this needs to be handwritten
203    assembly, but since that's what this file contains, here's a
204    simple strlen implementation (written in C and compiled by gcc.)
206 .global VG_(amd64_linux_REDIR_FOR_strlen)
207 .type   VG_(amd64_linux_REDIR_FOR_strlen), @function
208 VG_(amd64_linux_REDIR_FOR_strlen):
209 .LfnB5:
210         xorl    %eax, %eax
211         cmpb    $0, (%rdi)
212         movq    %rdi, %rdx
213         je      .L41
214 .L40:   addq    $1, %rdx
215         cmpb    $0, (%rdx)
216         jne     .L40
217         movq    %rdx, %rax
218         subq    %rdi, %rax
219 .L41:   ret
220 .LfnE5:
221 .size VG_(amd64_linux_REDIR_FOR_strlen), .-VG_(amd64_linux_REDIR_FOR_strlen)
224 /* A CIE for the above four functions, followed by their FDEs */
225         .section .eh_frame,"a",@progbits
226 .Lframe1:
227         .long   .LEcie1-.LScie1
228 .LScie1:
229         .long   0x0
230         .byte   0x1
231         .string "zR"
232         .uleb128 0x1
233         .sleb128 -8
234         .byte   0x10
235         .uleb128 0x1
236         .byte   0x3
237         .byte   0xc
238         .uleb128 0x7
239         .uleb128 0x8
240         .byte   0x90
241         .uleb128 0x1
242         .align 8
243 .LEcie1:
244 .LSfde2:
245         .long   .LEfde2-.LASfde2
246 .LASfde2:
247         .long   .LASfde2-.Lframe1
248         .long   .LfnB2
249         .long   .LfnE2-.LfnB2
250         .uleb128 0x0
251         .align 8
252 .LEfde2:
253 .LSfde3:
254         .long   .LEfde3-.LASfde3
255 .LASfde3:
256         .long   .LASfde3-.Lframe1
257         .long   .LfnB3
258         .long   .LfnE3-.LfnB3
259         .uleb128 0x0
260         .align 8
261 .LEfde3:
262 .LSfde4:
263         .long   .LEfde4-.LASfde4
264 .LASfde4:
265         .long   .LASfde4-.Lframe1
266         .long   .LfnB4
267         .long   .LfnE4-.LfnB4
268         .uleb128 0x0
269         .align 8
270 .LEfde4:
271 .LSfde5:
272         .long   .LEfde5-.LASfde5
273 .LASfde5:
274         .long   .LASfde5-.Lframe1
275         .long   .LfnB5
276         .long   .LfnE5-.LfnB5
277         .uleb128 0x0
278         .align 8
279 .LEfde5:
280         .previous
282 .global VG_(trampoline_stuff_end)
283 VG_(trampoline_stuff_end):
285         /* and a trailing page of unexecutable code */
286         UD2_PAGE
288 #       undef UD2_16
289 #       undef UD2_64
290 #       undef UD2_256
291 #       undef UD2_1024
292 #       undef UD2_PAGE
294 /*---------------- ppc32-linux ----------------*/
295 #else
296 #if defined(VGP_ppc32_linux)
298 #       define UD2_16     trap ; trap ; trap; trap
299 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
300 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
301 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
302 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
304         /* a leading page of unexecutable code */
305         UD2_PAGE
307 .global VG_(trampoline_stuff_start)
308 VG_(trampoline_stuff_start):
310 .global VG_(ppc32_linux_SUBST_FOR_sigreturn)
311 VG_(ppc32_linux_SUBST_FOR_sigreturn):
312         li 0,__NR_sigreturn
313         sc
314         .long 0 /*illegal insn*/
316 .global VG_(ppc32_linux_SUBST_FOR_rt_sigreturn)
317 VG_(ppc32_linux_SUBST_FOR_rt_sigreturn):
318         li 0,__NR_rt_sigreturn
319         sc
320         .long 0 /*illegal insn*/
321         
322 /* There's no particular reason that this needs to be handwritten
323    assembly, but since that's what this file contains, here's a
324    simple strlen implementation (written in C and compiled by gcc.)
326 .global VG_(ppc32_linux_REDIR_FOR_strlen)
327 .type   VG_(ppc32_linux_REDIR_FOR_strlen), @function
328 VG_(ppc32_linux_REDIR_FOR_strlen):
329         lbz 4,0(3)
330         li 9,0
331         cmpwi 0,4,0
332         beq- 0,.L18
333 .L19:
334         lbzu 5,1(3)
335         addi 9,9,1
336         cmpwi 0,5,0
337         bne+ 0,.L19
338 .L18:
339         mr 3,9
340         blr
341 .size VG_(ppc32_linux_REDIR_FOR_strlen), .-VG_(ppc32_linux_REDIR_FOR_strlen)
343 /* Ditto strcmp */
344 .global VG_(ppc32_linux_REDIR_FOR_strcmp)
345 .type   VG_(ppc32_linux_REDIR_FOR_strcmp), @function
346 VG_(ppc32_linux_REDIR_FOR_strcmp):
347 .L20:
348         lbz 0,0(3)
349         cmpwi 7,0,0
350         bne- 7,.L21
351         lbz 0,0(4)
352         li 11,0
353         cmpwi 7,0,0
354         beq- 7,.L22
355 .L21:
356         lbz 0,0(3)
357         li 11,-1
358         cmpwi 7,0,0
359         beq- 7,.L22
360         lbz 0,0(4)
361         li 11,1
362         cmpwi 7,0,0
363         beq- 7,.L22
364         lbz 9,0(3)
365         lbz 0,0(4)
366         li 11,-1
367         cmplw 7,9,0
368         blt- 7,.L22
369         lbz 9,0(3)
370         lbz 0,0(4)
371         li 11,1
372         addi 3,3,1
373         addi 4,4,1
374         cmplw 7,9,0
375         ble+ 7,.L20
376 .L22:
377         mr 3,11
378         blr
379 .size VG_(ppc32_linux_REDIR_FOR_strcmp), .-VG_(ppc32_linux_REDIR_FOR_strcmp)
381 /* Ditto index/strchr */
382 .global VG_(ppc32_linux_REDIR_FOR_strchr)
383 .type   VG_(ppc32_linux_REDIR_FOR_strchr), @function
384 VG_(ppc32_linux_REDIR_FOR_strchr):
385         lbz 0,0(3)
386         rlwinm 4,4,0,0xff
387         cmpw 7,4,0
388         beqlr 7
389         cmpwi 7,0,0
390         bne 7,.L308
391         b .L304
392 .L309:  
393         beq 6,.L304
394 .L308:  
395         lbzu 0,1(3)
396         cmpw 7,4,0
397         cmpwi 6,0,0
398         bne 7,.L309
399         blr
400 .L304:  
401         li 3,0
402         blr
403 .size   VG_(ppc32_linux_REDIR_FOR_strchr),.-VG_(ppc32_linux_REDIR_FOR_strchr)
404         
405 .global VG_(trampoline_stuff_end)
406 VG_(trampoline_stuff_end):
408         /* and a trailing page of unexecutable code */
409         UD2_PAGE
411 #       undef UD2_16
412 #       undef UD2_64
413 #       undef UD2_256
414 #       undef UD2_1024
415 #       undef UD2_PAGE
417 /*---------------- ppc64-linux ----------------*/
418 #else
419 #if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
421 #       define UD2_16     trap ; trap ; trap; trap
422 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
423 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
424 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
425 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
427         /* a leading page of unexecutable code */
428         UD2_PAGE
430 .global VG_(trampoline_stuff_start)
431 VG_(trampoline_stuff_start):
433 .global VG_(ppc64_linux_SUBST_FOR_rt_sigreturn)
434 VG_(ppc64_linux_SUBST_FOR_rt_sigreturn):
435         li 0,__NR_rt_sigreturn
436         sc
437         .long 0 /*illegal insn*/
439         /* See comment in pub_core_trampoline.h for what this is for */
440 .global VG_(ppctoc_magic_redirect_return_stub)
441 VG_(ppctoc_magic_redirect_return_stub):
442         trap
444         /* this function is written using the "dotless" ABI convention */
445         .align 2
446         .globl VG_(ppc64_linux_REDIR_FOR_strlen)
447 #if !defined VGP_ppc64be_linux || _CALL_ELF == 2
448         /* Little Endian uses ELF version 2 */
449         .type VG_(ppc64_linux_REDIR_FOR_strlen),@function
450 VG_(ppc64_linux_REDIR_FOR_strlen):
451 #else
452         /* Big Endian uses ELF version 1 */
453         .section        ".opd","aw"
454         .align 3
455 VG_(ppc64_linux_REDIR_FOR_strlen):
456         .quad   .L.VG_(ppc64_linux_REDIR_FOR_strlen),.TOC.@tocbase,0
457         .previous
458         .size   VG_(ppc64_linux_REDIR_FOR_strlen), \
459                         .L0end-.L.VG_(ppc64_linux_REDIR_FOR_strlen)
460         .type   VG_(ppc64_linux_REDIR_FOR_strlen), @function
462 .L.VG_(ppc64_linux_REDIR_FOR_strlen):
463 #endif
464 #if _CALL_ELF == 2
465 0:      addis        2,12,.TOC.-0b@ha
466         addi         2,2,.TOC.-0b@l
467         .localentry  VG_(ppc64_linux_REDIR_FOR_strlen), .-VG_(ppc64_linux_REDIR_FOR_strlen)
468 #endif
469         mr 9,3
470         lbz 0,0(3)
471         li 3,0
472         cmpwi 7,0,0
473         beqlr 7
474         li 3,0
475 .L01:
476         addi 0,3,1
477         extsw 3,0
478         lbzx 0,9,3
479         cmpwi 7,0,0
480         bne 7,.L01
481         blr
483 #if !defined VGP_ppc64be_linux || _CALL_ELF == 2
484         .size VG_(ppc64_linux_REDIR_FOR_strlen),.-VG_(ppc64_linux_REDIR_FOR_strlen)
485 #else
486         .size VG_(ppc64_linux_REDIR_FOR_strlen),.-.L.VG_(ppc64_linux_REDIR_FOR_strlen)
487 #endif
488         .long 0
489         .byte 0,0,0,0,0,0,0,0
490 .L0end:
492         /* this function is written using the "dotless" ABI convention */
493         .align 2
494         .globl VG_(ppc64_linux_REDIR_FOR_strchr)
495 #if !defined VGP_ppc64be_linux || _CALL_ELF == 2
496         .type   VG_(ppc64_linux_REDIR_FOR_strchr),@function
497 VG_(ppc64_linux_REDIR_FOR_strchr):
498 #else
499         .section        ".opd","aw"
500         .align 3
501 VG_(ppc64_linux_REDIR_FOR_strchr):
502         .quad   .L.VG_(ppc64_linux_REDIR_FOR_strchr),.TOC.@tocbase,0
503         .previous
504         .size   VG_(ppc64_linux_REDIR_FOR_strchr), \
505                         .L1end-.L.VG_(ppc64_linux_REDIR_FOR_strchr)
506         .type   VG_(ppc64_linux_REDIR_FOR_strchr),@function
508 .L.VG_(ppc64_linux_REDIR_FOR_strchr):
509 #endif
510 #if  _CALL_ELF == 2
511 0:      addis         2,12,.TOC.-0b@ha
512         addi         2,2,.TOC.-0b@l
513         .localentry VG_(ppc64_linux_REDIR_FOR_strchr), .-VG_(ppc64_linux_REDIR_FOR_strchr)
514 #endif
515         lbz 0,0(3)
516         rldicl 4,4,0,56
517         cmpw 7,4,0
518         beqlr 7
519         cmpdi 7,0,0
520         bne 7,.L18
521         b .L14
522 #if !defined VGP_ppc64be_linux || _CALL_ELF == 2
523         .size VG_(ppc64_linux_REDIR_FOR_strchr),.-VG_(ppc64_linux_REDIR_FOR_strchr)
524 #else
525         .size VG_(ppc64_linux_REDIR_FOR_strchr),.-.L.VG_(ppc64_linux_REDIR_FOR_strchr)
526 #endif
527 .L19:   
528         beq 6,.L14
529 .L18:   
530         lbzu 0,1(3)
531         cmpw 7,4,0
532         cmpdi 6,0,0
533         bne 7,.L19
534         blr
535 .L14:   
536         li 3,0
537         blr
538         .long 0
539         .byte 0,0,0,0,0,0,0,0
540 .L1end:
542         
543 .global VG_(trampoline_stuff_end)
544 VG_(trampoline_stuff_end):
546         /* and a trailing page of unexecutable code */
547         UD2_PAGE
549 #       undef UD2_16
550 #       undef UD2_64
551 #       undef UD2_256
552 #       undef UD2_1024
553 #       undef UD2_PAGE
555 /*---------------- arm-linux ----------------*/
556 #else
557 #if defined(VGP_arm_linux)
559 #       define UD2_4      .word 0xFFFFFFFF
560 #       define UD2_16     UD2_4    ; UD2_4    ; UD2_4    ; UD2_4
561 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
562 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
563 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
564 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
566         /* a leading page of unexecutable code */
567         UD2_PAGE
569 .global VG_(trampoline_stuff_start)
570 VG_(trampoline_stuff_start):
572 .global VG_(arm_linux_SUBST_FOR_sigreturn)
573 .type   VG_(arm_linux_SUBST_FOR_sigreturn),#function
574 VG_(arm_linux_SUBST_FOR_sigreturn):
575         mov r7, # __NR_sigreturn
576         svc #0
577         .long 0xFFFFFFFF /*illegal insn*/
578 .size VG_(arm_linux_SUBST_FOR_sigreturn), .-VG_(arm_linux_SUBST_FOR_sigreturn)
580 .global VG_(arm_linux_SUBST_FOR_rt_sigreturn)
581 .type   VG_(arm_linux_SUBST_FOR_rt_sigreturn),#function
582 VG_(arm_linux_SUBST_FOR_rt_sigreturn):
583         mov r7, # __NR_rt_sigreturn
584         svc #0
585         .long 0xFFFFFFFF /*illegal insn*/
586 .size VG_(arm_linux_SUBST_FOR_rt_sigreturn), .-VG_(arm_linux_SUBST_FOR_rt_sigreturn)
587         
588 .global VG_(arm_linux_REDIR_FOR_strlen)
589 VG_(arm_linux_REDIR_FOR_strlen):
590         mov     r2, r0
591         ldrb    r0, [r0, #0]    @ zero_extendqisi2
592         @ lr needed for prologue
593         cmp     r0, #0
594         bxeq    lr
595         mov     r0, #0
596 .L5:
597         add     r0, r0, #1
598         ldrb    r3, [r0, r2]    @ zero_extendqisi2
599         cmp     r3, #0
600         bne     .L5
601         bx      lr
602         UD2_4
604 //.global VG_(arm_linux_REDIR_FOR_index)
605 //VG_(arm_linux_REDIR_FOR_index):
606 //      ldrb    r3, [r0, #0]    @ zero_extendqisi2
607 //      and     r1, r1, #255
608 //      cmp     r3, r1
609 //      @ lr needed for prologue
610 //      bne     .L9
611 //      bx      lr
612 //.L12:
613 //      ldrb    r3, [r0, #1]!   @ zero_extendqisi2
614 //      cmp     r3, r1
615 //      beq     .L11
616 //.L9:
617 //      cmp     r3, #0
618 //      bne     .L12
619 //      mov     r0, #0
620 //      bx      lr
621 //.L11:
622 //      bx      lr
623 //      UD2_4
625 .global VG_(arm_linux_REDIR_FOR_memcpy)
626 VG_(arm_linux_REDIR_FOR_memcpy):
627         stmfd   sp!, {r4, r5, lr}
628         subs    lr, r2, #0
629         mov     r5, r0
630         beq     .L2
631         cmp     r0, r1
632         bls     .L4
633         add     r3, r0, lr
634         add     r1, lr, r1
635         cmp     lr, #3
636         sub     r4, r3, #1
637         sub     r0, r1, #1
638         ble     .L28
639         sub     ip, r3, #5
640         sub     r1, r1, #5
641 .L8:
642         ldrb    r3, [r1, #4]    @ zero_extendqisi2
643         sub     lr, lr, #4
644         strb    r3, [ip, #4]
645         ldrb    r2, [r1, #3]    @ zero_extendqisi2
646         cmp     lr, #3
647         strb    r2, [ip, #3]
648         ldrb    r3, [r1, #2]    @ zero_extendqisi2
649         mov     r4, ip
650         strb    r3, [ip, #2]
651         ldrb    r2, [r1, #1]    @ zero_extendqisi2
652         mov     r0, r1
653         strb    r2, [ip, #1]
654         sub     r1, r1, #4
655         sub     ip, ip, #4
656         bgt     .L8
657         cmp     lr, #0
658         beq     .L2
659 .L28:
660         sub     r2, lr, #1
661 .L21:
662         sub     r2, r2, #1
663         ldrb    r3, [r0], #-1   @ zero_extendqisi2
664         cmn     r2, #1
665         strb    r3, [r4], #-1
666         bne     .L21
667 .L2:
668         mov     r0, r5
669         ldmfd   sp!, {r4, r5, pc}
670 .L4:
671         bcs     .L2
672         cmp     lr, #3
673         mov     ip, r0
674         ble     .L29
675 .L19:
676         ldrb    r3, [r1, #0]    @ zero_extendqisi2
677         sub     lr, lr, #4
678         strb    r3, [ip, #0]
679         ldrb    r2, [r1, #1]    @ zero_extendqisi2
680         cmp     lr, #3
681         strb    r2, [ip, #1]
682         ldrb    r3, [r1, #2]    @ zero_extendqisi2
683         strb    r3, [ip, #2]
684         ldrb    r2, [r1, #3]    @ zero_extendqisi2
685         add     r1, r1, #4
686         strb    r2, [ip, #3]
687         add     ip, ip, #4
688         bgt     .L19
689         cmp     lr, #0
690         beq     .L2
691 .L29:
692         sub     r2, lr, #1
693 .L20:
694         sub     r2, r2, #1
695         ldrb    r3, [r1], #1    @ zero_extendqisi2
696         cmn     r2, #1
697         strb    r3, [ip], #1
698         bne     .L20
699         mov     r0, r5
700         ldmfd   sp!, {r4, r5, pc}
701         UD2_4
703 .global VG_(arm_linux_REDIR_FOR_strcmp)
704 VG_(arm_linux_REDIR_FOR_strcmp):
705 .L64:
706         ldrb    r3, [r0], #1    @ zero_extendqisi2
707         ldrb    r2, [r1], #1    @ zero_extendqisi2
708         cmp     r3, #0
709         beq     .L67
710         cmp     r3, r2
711         beq     .L64
712         rsb     r0, r2, r3
713         bx      lr
714 .L67:
715         rsb     r0, r2, #0
716         bx      lr
717         UD2_4
719 .global VG_(trampoline_stuff_end)
720 VG_(trampoline_stuff_end):
722         /* and a trailing page of unexecutable code */
723         UD2_PAGE
725 #       undef UD2_4
726 #       undef UD2_16
727 #       undef UD2_64
728 #       undef UD2_256
729 #       undef UD2_1024
730 #       undef UD2_PAGE
731         
732 /*---------------- arm64-linux ----------------*/
733 #else
734 #if defined(VGP_arm64_linux)
736 #       define UD2_4      .word 0xFFFFFFFF
737 #       define UD2_16     UD2_4    ; UD2_4    ; UD2_4    ; UD2_4
738 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
739 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
740 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
741 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
743         /* a leading page of unexecutable code */
744         UD2_PAGE
746 .global VG_(trampoline_stuff_start)
747 VG_(trampoline_stuff_start):
749 .global VG_(arm64_linux_SUBST_FOR_rt_sigreturn)
750 .type   VG_(arm64_linux_SUBST_FOR_rt_sigreturn),#function
751 VG_(arm64_linux_SUBST_FOR_rt_sigreturn):
752         mov x8, # __NR_rt_sigreturn
753         svc #0
754         .long 0xFFFFFFFF /*illegal insn*/
755 .size VG_(arm64_linux_SUBST_FOR_rt_sigreturn), \
756         .-VG_(arm64_linux_SUBST_FOR_rt_sigreturn)
758 .global VG_(arm64_linux_REDIR_FOR_strlen)
759 .type   VG_(arm64_linux_REDIR_FOR_strlen),#function
760 VG_(arm64_linux_REDIR_FOR_strlen):
761         mov     x2, x0
762         ldrb    w0, [x0]
763         cbz     w0, .L5
764         mov     x0, 0
765 .L4:
766         add     x0, x0, 1
767         ldrb    w1, [x2,x0]
768         cbnz    w1, .L4
769         ret
770 .L5:
771         mov     x0, 0
772         ret
773 .size VG_(arm64_linux_REDIR_FOR_strlen), .-VG_(arm64_linux_REDIR_FOR_strlen)
775 .global VG_(arm64_linux_REDIR_FOR_index)
776 .type   VG_(arm64_linux_REDIR_FOR_index),#function
777 VG_(arm64_linux_REDIR_FOR_index):
778         ldrb    w2, [x0]
779         uxtb    w1, w1
780         cmp     w2, w1
781         beq     .L11
782 .L13:
783         cbz     w2, .L16
784         ldrb    w2, [x0,1]!
785         cmp     w2, w1
786         bne     .L13
787 .L11:
788         ret
789 .L16:
790         mov     x0, 0
791         ret
792 .size VG_(arm64_linux_REDIR_FOR_index), .-VG_(arm64_linux_REDIR_FOR_index)
794 .global VG_(arm64_linux_REDIR_FOR_strcmp)
795 .type   VG_(arm64_linux_REDIR_FOR_strcmp),#function
796 VG_(arm64_linux_REDIR_FOR_strcmp):
797         ldrb    w2, [x0]
798         ldrb    w3, [x1]
799         cmp     w2, w3
800         bcc     .L22
801 .L21:
802         bhi     .L25
803         cbz     w2, .L26
804         ldrb    w2, [x0,1]!
805         ldrb    w3, [x1,1]!
806         cmp     w2, w3
807         bcs     .L21
808 .L22:
809         mov     x0, -1
810         ret
811 .L25:
812         mov     x0, 1
813         ret
814 .L26:
815         mov     x0, 0
816         ret
817 .size VG_(arm64_linux_REDIR_FOR_strcmp), .-VG_(arm64_linux_REDIR_FOR_strcmp)
819 .global VG_(trampoline_stuff_end)
820 VG_(trampoline_stuff_end):
822         /* and a trailing page of unexecutable code */
823         UD2_PAGE
825 #       undef UD2_4
826 #       undef UD2_16
827 #       undef UD2_64
828 #       undef UD2_256
829 #       undef UD2_1024
830 #       undef UD2_PAGE
831         
832 /*---------------- x86-darwin ----------------*/
833 #else
834 #if defined(VGP_x86_darwin)
836         /* a leading page of unexecutable code */
837 .fill 2048, 2, 0x0b0f /* `ud2` */
839 .globl VG_(trampoline_stuff_start)
840 VG_(trampoline_stuff_start):
842 .globl VG_(x86_darwin_SUBST_FOR_sigreturn)
843 VG_(x86_darwin_SUBST_FOR_sigreturn):
844         /* XXX does this need to have any special form? (cf x86-linux
845         version) */
846         movl    $ __NR_DARWIN_FAKE_SIGRETURN, %eax
847         int     $0x80
848         ud2
850 .globl VG_(x86_darwin_REDIR_FOR_strlen)
851 VG_(x86_darwin_REDIR_FOR_strlen):
852         movl    4(%esp), %edx
853         movl    %edx, %eax
854         jmp     1f
856         incl    %eax
858         cmpb    $0, (%eax)
859         jne     0b
860         subl    %edx, %eax
861         ret
863 .globl VG_(x86_darwin_REDIR_FOR_strcat)
864 VG_(x86_darwin_REDIR_FOR_strcat):
865         pushl   %esi
866         movl    8(%esp), %esi
867         movl    12(%esp), %ecx
868         movl    %esi, %edx
869         jmp     1f
871         incl    %edx
873         cmpb    $0, (%edx)
874         jne     0b
876         movzbl  (%ecx), %eax
877         incl    %ecx
878         movb    %al, (%edx)
879         incl    %edx
880         testb   %al, %al
881         jne     2b
882         movl    %esi, %eax
883         popl    %esi
884         ret
887 .globl VG_(x86_darwin_REDIR_FOR_strcmp)
888 VG_(x86_darwin_REDIR_FOR_strcmp):
889         movl    4(%esp), %edx
890         movl    8(%esp), %ecx
891         jmp     1f
893         incl    %edx
894         incl    %ecx
896         movzbl  (%edx), %eax
897         testb   %al, %al
898         je      2f
899         cmpb    (%ecx), %al
900         je      0b
902         movzbl  (%ecx),%edx
903         movzbl  %al,%eax
904         subl    %edx, %eax
905         ret
908 .globl VG_(x86_darwin_REDIR_FOR_strcpy)
909 VG_(x86_darwin_REDIR_FOR_strcpy):
910         pushl   %ebp
911         movl    %esp, %ebp
912         pushl   %esi
913         movl    8(%ebp), %esi
914         movl    12(%ebp), %ecx
915         movl    %esi, %edx
916         jmp     1f
918         incl    %ecx
919         incl    %edx
921         movzbl  (%ecx), %eax
922         testb   %al, %al
923         movb    %al, (%edx)
924         jne     0b
925         movl    %esi, %eax
926         popl    %esi
927         leave
928         ret
930 .globl VG_(x86_darwin_REDIR_FOR_strlcat)
931 VG_(x86_darwin_REDIR_FOR_strlcat):
932         pushl   %ebp
933         movl    %esp, %ebp
934         pushl   %edi
935         pushl   %esi
936         subl    $16, %esp
937         movl    8(%ebp), %esi
938         movl    16(%ebp), %ecx
939         movl    %esi, %edx
940         leal    (%ecx,%esi), %eax
941         jmp     1f
943         incl    %edx
945         cmpl    %edx, %eax
946         je      2f
947         cmpb    $0, (%edx)
948         jne     0b
950         movl    %edx, %edi
951         subl    %esi, %edi
952         movl    %ecx, %esi
953         subl    %edi, %esi
954         je      3f
955         movl    12(%ebp), %eax
956         jmp     6f
958         movl    12(%ebp), %eax
959         movl    %eax, (%esp)
960         call    VG_(x86_darwin_REDIR_FOR_strlen)
961         jmp     7f
963         cmpl    $1, %esi
964         je      5f
965         movb    %cl, (%edx)
966         decl    %esi
967         incl    %edx
969         incl    %eax
971         movzbl  (%eax), %ecx
972         testb   %cl, %cl
973         jne     4b
974         movb    $0, (%edx)
975         subl    12(%ebp), %eax
977         addl    $16, %esp
978         leal    (%edi,%eax), %eax
979         popl    %esi
980         popl    %edi
981         leave
982         ret
983         
984         
985 .globl VG_(trampoline_stuff_end)
986 VG_(trampoline_stuff_end):
988         /* a trailing page of unexecutable code */
989 .fill 2048, 2, 0x0b0f /* `ud2` */
992 /*---------------- amd64-darwin ----------------*/
993 #else
994 #if defined(VGP_amd64_darwin)
996         /* a leading page of unexecutable code */
997 .fill 2048, 2, 0x0b0f /* `ud2` */
999 .globl VG_(trampoline_stuff_start)
1000 VG_(trampoline_stuff_start):
1002 .globl VG_(amd64_darwin_SUBST_FOR_sigreturn)
1003 VG_(amd64_darwin_SUBST_FOR_sigreturn):
1004         /* XXX does this need to have any special form? (cf x86-linux
1005         version) */
1006         movq    $ __NR_DARWIN_FAKE_SIGRETURN, %rax
1007         syscall
1008         ud2
1010 .globl VG_(amd64_darwin_REDIR_FOR_strlen)
1011 VG_(amd64_darwin_REDIR_FOR_strlen):
1012         movq    %rdi, %rax
1013         jmp     1f
1015         incq    %rax
1017         cmpb    $0, (%rax)
1018         jne     0b
1019         subq    %rdi, %rax
1020         ret
1022 .globl VG_(amd64_darwin_REDIR_FOR_strcat)
1023 VG_(amd64_darwin_REDIR_FOR_strcat):
1024         movq    %rdi, %rdx
1025         jmp     1f
1027         incq    %rdx
1029         cmpb    $0, (%rdx)
1030         jne     0b
1032         movzbl  (%rsi), %eax
1033         incq    %rsi
1034         movb    %al, (%rdx)
1035         incq    %rdx
1036         testb   %al, %al
1037         jne     2b
1038         movq    %rdi, %rax
1039         ret
1042 .globl VG_(amd64_darwin_REDIR_FOR_strcmp)
1043 VG_(amd64_darwin_REDIR_FOR_strcmp):
1044         jmp     1f
1046         incq    %rdi
1047         incq    %rsi
1049         movzbl  (%rdi), %eax
1050         testb   %al, %al
1051         je      2f
1052         cmpb    (%rsi), %al
1053         je      0b
1055         movzbl  (%rsi), %edx
1056         movzbl  %al, %eax
1057         subl    %edx, %eax
1058         ret
1060 .globl VG_(amd64_darwin_REDIR_FOR_strcpy)
1061 VG_(amd64_darwin_REDIR_FOR_strcpy):
1062         pushq   %rbp
1063         movq    %rdi, %rdx
1064         movq    %rsp, %rbp
1065         jmp     1f
1067         incq    %rsi
1068         incq    %rdx
1070         movzbl  (%rsi), %eax
1071         testb   %al, %al
1072         movb    %al, (%rdx)
1073         jne     0b
1074         leave
1075         movq    %rdi, %rax
1076         ret
1077         
1078 .globl VG_(amd64_darwin_REDIR_FOR_strlcat)
1079 VG_(amd64_darwin_REDIR_FOR_strlcat):
1080         pushq   %rbp
1081         leaq    (%rdx,%rdi), %rax
1082         movq    %rdi, %rcx
1083         movq    %rsp, %rbp
1084         pushq   %rbx
1085         subq    $8, %rsp
1086         jmp     1f
1088         incq    %rcx
1090         cmpq    %rcx, %rax
1091         je      2f
1092         cmpb    $0, (%rcx)
1093         jne     0b
1095         movq    %rcx, %rbx
1096         subq    %rdi, %rbx
1097         movq    %rdx, %rdi
1098         subq    %rbx, %rdi
1099         je      3f
1100         movq    %rsi, %rax
1101         jmp     6f
1103         movq    %rsi, %rdi
1104         call    VG_(amd64_darwin_REDIR_FOR_strlen)
1105         jmp     7f
1107         cmpq    $1, %rdi
1108         je      5f
1109         movb    %dl, (%rcx)
1110         decq    %rdi
1111         incq    %rcx
1113         incq    %rax
1115         movzbl  (%rax), %edx
1116         testb   %dl, %dl
1117         jne     4b
1118         movb    $0, (%rcx)
1119         subq    %rsi, %rax
1121         leaq    (%rbx,%rax), %rax
1122         addq    $8, %rsp
1123         popq    %rbx
1124         leave
1125         ret
1127 .globl VG_(amd64_darwin_REDIR_FOR_arc4random)
1128 VG_(amd64_darwin_REDIR_FOR_arc4random):
1129         /* not very random, hope dyld won't mind */
1130         movq    $0x76616c6772696e64, %rax
1131         ret
1133 .globl VG_(amd64_darwin_REDIR_FOR_strchr)
1134 VG_(amd64_darwin_REDIR_FOR_strchr):
1135         pushq   %rbp
1136         movq    %rsp, %rbp
1137         movb    (%rdi), %cl
1138         cmpb    %sil, %cl
1139         jne     1f
1140         movq    %rdi, %rax
1141         popq    %rbp
1142         ret
1144         testb   %cl, %cl
1145         movl    $0, %eax
1146         je      2f
1147         movb    1(%rdi), %cl
1148         incq    %rdi
1149         cmpb    %sil, %cl
1150         movq    %rdi, %rax
1151         jne     1b
1153         popq    %rbp
1154         ret
1155         
1156 .globl VG_(trampoline_stuff_end)
1157 VG_(trampoline_stuff_end):
1159         /* a trailing page of unexecutable code */
1160 .fill 2048, 2, 0x0b0f /* `ud2` */
1163 /*---------------- s390x-linux ----------------*/
1164 #else
1165 #if defined(VGP_s390x_linux)
1167         /* a leading page of unexecutable code */
1168         .fill 2048, 2, 0x0000
1170 .global VG_(trampoline_stuff_start)
1171 VG_(trampoline_stuff_start):
1173 .global VG_(s390x_linux_SUBST_FOR_sigreturn)
1174 VG_(s390x_linux_SUBST_FOR_sigreturn):
1175         svc __NR_sigreturn
1176         .short 0
1178 .global VG_(s390x_linux_SUBST_FOR_rt_sigreturn)
1179 VG_(s390x_linux_SUBST_FOR_rt_sigreturn):
1180         /* Old gcc unwinding code checks for a sig(_rt)_return svc and then
1181            for ra = cfa to decide if it is a sig_rt_frame or not. Since we
1182            set ra to this trampoline, but the cfa is still in the stack,
1183            the unwinder thinks, that this is a non-rt frame  and causes a
1184            crash in the gcc unwinder - which is used by the thread library
1185            and others. Therefore we add a lr 1,1 nop, to let the gcc
1186            unwinder bail out gracefully. This might also affect unwinding
1187            across the signal frame - tough luck. fixs390 */
1188         lr 1,1
1189         svc __NR_rt_sigreturn
1190         .short 0
1192 .global VG_(s390x_linux_REDIR_FOR_index)
1193 .type   VG_(s390x_linux_REDIR_FOR_index),@function
1194 VG_(s390x_linux_REDIR_FOR_index):
1196 #   %r2 = addess of string
1197 #   %r3 = character to find
1199         lghi    %r0,255
1200         ngr     %r0,%r3        # r0 = (unsigned char)r3
1201         lghi    %r4,0
1202 .L1:
1203         llgc    %r1,0(%r2)     # r1 = byte from string
1204         cr      %r1,%r0        # compare
1205         ber     %r14           # return if found
1206         cr      %r1,%r4        # end of string ?
1207         je      .L2
1208         aghi    %r2,1          # increment r2
1209         j       .L1
1210 .L2:    lghi    %r2,0          # return value 0
1211         br      %r14
1212 .size VG_(s390x_linux_REDIR_FOR_index), .-VG_(s390x_linux_REDIR_FOR_index)
1214 .globl VG_(trampoline_stuff_end)
1215 VG_(trampoline_stuff_end):
1216         .fill 2048, 2, 0x0000
1218 /*---------------------- mips32-linux ----------------------*/
1219 #else
1220 #if defined(VGP_mips32_linux)
1222 #       define UD2_16     trap ; trap ; trap; trap
1223 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
1224 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
1225 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
1226 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
1229 .global VG_(trampoline_stuff_start)
1230 VG_(trampoline_stuff_start):
1232 .global VG_(mips32_linux_SUBST_FOR_sigreturn)
1233 VG_(mips32_linux_SUBST_FOR_sigreturn):
1234         li $v0,__NR_sigreturn
1235         syscall
1236         nop
1237         .long 0 /*illegal insn*/
1239 .global VG_(mips32_linux_SUBST_FOR_rt_sigreturn)
1240 VG_(mips32_linux_SUBST_FOR_rt_sigreturn):
1241         li $v0,__NR_rt_sigreturn
1242         syscall
1243         nop
1244         .long 0 /*illegal insn*/
1245         
1246 /* There's no particular reason that this needs to be handwritten
1247    assembly, but since that's what this file contains, here's a
1248    simple strlen implementation (written in C and compiled by gcc.)
1250 .global VG_(mips32_linux_REDIR_FOR_strlen)
1251 .type   VG_(mips32_linux_REDIR_FOR_strlen), @function
1252 VG_(mips32_linux_REDIR_FOR_strlen):
1253       li $v0, 0
1254       //la $a0, string
1255       j strlen_cond
1256    strlen_loop:
1257       addi $v0, $v0, 1
1258       addi $a0, $a0, 1
1259    strlen_cond:
1260       lbu $t0, ($a0)
1261       bne $t0, $zero, strlen_loop
1262     jr $ra
1264 .size VG_(mips32_linux_REDIR_FOR_strlen), .-VG_(mips32_linux_REDIR_FOR_strlen)
1266 .global VG_(trampoline_stuff_end)
1267 VG_(trampoline_stuff_end):
1270 #       undef UD2_16
1271 #       undef UD2_64
1272 #       undef UD2_256
1273 #       undef UD2_1024
1274 #       undef UD2_PAGE
1276 /*---------------------- mips64-linux ----------------------*/
1277 #else
1278 #if defined(VGP_mips64_linux)
1280 #       define UD2_16     trap ; trap ; trap; trap
1281 #       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
1282 #       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
1283 #       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
1284 #       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
1286 .global VG_(trampoline_stuff_start)
1287 VG_(trampoline_stuff_start):
1289 .global VG_(mips64_linux_SUBST_FOR_rt_sigreturn)
1290 VG_(mips64_linux_SUBST_FOR_rt_sigreturn):
1291         li $2,__NR_rt_sigreturn
1292         syscall
1293         nop
1294         .long 0 /*illegal insn*/
1296 /* There's no particular reason that this needs to be handwritten
1297    assembly, but since that's what this file contains, here's a
1298    simple strlen implementation (written in C and compiled by gcc.)
1300 .global VG_(mips64_linux_REDIR_FOR_strlen)
1301 .type   VG_(mips64_linux_REDIR_FOR_strlen), @function
1302 VG_(mips64_linux_REDIR_FOR_strlen):
1303         lbu $12, 0($4)
1304         li  $13, 0
1305         beq $12, $0, M01 
1306         nop
1308 M02: 
1309         addiu $13, $13, 1 
1310         addiu $4, $4, 1 
1311         lbu $12, 0($4) 
1312         bne $12, $0, M02 
1313         nop 
1315 M01: 
1316         move $2, $13 
1317         jr $31 
1318         nop
1320 .size VG_(mips64_linux_REDIR_FOR_strlen), .-VG_(mips64_linux_REDIR_FOR_strlen)
1322 .global VG_(trampoline_stuff_end)
1323 VG_(trampoline_stuff_end):
1326 #       undef UD2_16
1327 #       undef UD2_64
1328 #       undef UD2_256
1329 #       undef UD2_1024
1330 #       undef UD2_PAGE
1332 /*---------------- unknown ----------------*/
1333 #else
1334 #  error Unknown platform
1336 #endif
1337 #endif
1338 #endif
1339 #endif
1340 #endif
1341 #endif
1342 #endif
1343 #endif
1344 #endif
1345 #endif
1346 #endif
1348 #if defined(VGO_linux)
1349 /* Let the linker know we don't need an executable stack */
1350 #  if defined(VGP_arm_linux)
1351    .section .note.GNU-stack,"",%progbits
1352 #  else        
1353    .section .note.GNU-stack,"",@progbits
1354 #  endif
1355 #endif
1357 /*--------------------------------------------------------------------*/
1358 /*--- end                                                          ---*/
1359 /*--------------------------------------------------------------------*/