
/*--------------------------------------------------------------------*/
/*--- Trampoline code page stuff.                   m_trampoline.S ---*/
/*--------------------------------------------------------------------*/

/*
  This file is part of Valgrind, a dynamic binary instrumentation
  framework.

  Copyright (C) 2000-2017 Julian Seward 
     jseward@acm.org
  Copyright (C) 2006-2017 OpenWorks LLP
     info@open-works.co.uk
	
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
  published by the Free Software Foundation; either version 2 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, see <http://www.gnu.org/licenses/>.

  The GNU General Public License is contained in the file COPYING.
*/

#include "pub_core_basics_asm.h"
#include "pub_core_vkiscnums_asm.h"

/* ------------------ SIMULATED CPU HELPERS ------------------ */
/* 
   Replacements for some functions to do with vsyscalls and signals.
   This code runs on the simulated CPU.
*/
	
/*---------------------- x86-linux ----------------------*/
#if defined(VGP_x86_linux)

#	define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(x86_linux_SUBST_FOR_sigreturn)
VG_(x86_linux_SUBST_FOR_sigreturn):
        /* This is a very specific sequence which GDB uses to
           recognize signal handler frames.  Also gcc: see
           x86_fallback_frame_state() in
           gcc-4.1.0/gcc/config/i386/linux-unwind.h */
        popl    %eax
        movl    $ __NR_sigreturn, %eax
        int     $0x80
        ud2

.global VG_(x86_linux_SUBST_FOR_rt_sigreturn)
VG_(x86_linux_SUBST_FOR_rt_sigreturn):
        /* Likewise for rt signal frames */
        movl    $ __NR_rt_sigreturn, %eax
        int     $0x80
        ud2

/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple index implementation (written in C and compiled by gcc.)

   unsigned char* REDIR_FOR_index ( const char* s, int c ) 
   { 
      unsigned char  ch = (unsigned char)((unsigned int)c); 
      unsigned char* p  = (unsigned char*)s; 
      while (1) { 
         if (*p == ch) return p;
         if (*p == 0)  return 0; 
         p++; 
      } 
   }
*/
.global VG_(x86_linux_REDIR_FOR_index)
.type   VG_(x86_linux_REDIR_FOR_index), @function
VG_(x86_linux_REDIR_FOR_index):
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        movzbl  12(%ebp), %ecx
        movzbl  (%eax), %edx
        cmpb    %dl, %cl
        jne     .L9
        jmp     .L2
.L11:
        addl    $1, %eax
        movzbl  (%eax), %edx
        cmpb    %dl, %cl
        je      .L2
.L9:
        testb   %dl, %dl
        jne     .L11
        xorl    %eax, %eax
.L2:
        popl    %ebp
        ret
.size VG_(x86_linux_REDIR_FOR_index), .-VG_(x86_linux_REDIR_FOR_index)

/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple strlen implementation (written in C and compiled by gcc.)
*/
.global VG_(x86_linux_REDIR_FOR_strlen)
.type   VG_(x86_linux_REDIR_FOR_strlen), @function
VG_(x86_linux_REDIR_FOR_strlen):
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %edx
        movl    %edx, %eax
        jmp     2f
1:      incl    %eax
2:      cmpb    $0, (%eax)
        jne     1b
        subl    %edx, %eax
        popl    %ebp
        ret
.size VG_(x86_linux_REDIR_FOR_strlen), .-VG_(x86_linux_REDIR_FOR_strlen)


.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE
	
/*---------------------- amd64-linux ----------------------*/
#else
#if defined(VGP_amd64_linux)

#	define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(amd64_linux_SUBST_FOR_rt_sigreturn)
VG_(amd64_linux_SUBST_FOR_rt_sigreturn):
        /* This is a very specific sequence which GDB uses to
           recognize signal handler frames. */
        movq    $__NR_rt_sigreturn, %rax
        syscall
        ud2

.global VG_(amd64_linux_REDIR_FOR_vgettimeofday)
.type   VG_(amd64_linux_REDIR_FOR_vgettimeofday), @function
VG_(amd64_linux_REDIR_FOR_vgettimeofday):
.LfnB2:
        movq    $__NR_gettimeofday, %rax
        syscall
        ret
.LfnE2:
.size VG_(amd64_linux_REDIR_FOR_vgettimeofday), .-.LfnB2
	
.global VG_(amd64_linux_REDIR_FOR_vtime)
.type   VG_(amd64_linux_REDIR_FOR_vtime), @function
VG_(amd64_linux_REDIR_FOR_vtime):
.LfnB3:	
        movq    $__NR_time, %rax
        syscall
        ret
.LfnE3:
.size VG_(amd64_linux_REDIR_FOR_vtime), .-.LfnB3

.global VG_(amd64_linux_REDIR_FOR_vgetcpu)
.type   VG_(amd64_linux_REDIR_FOR_vgetcpu), @function
VG_(amd64_linux_REDIR_FOR_vgetcpu):
.LfnB4:
        movq    $__NR_getcpu, %rax
        syscall
        ret
.LfnE4:
.size VG_(amd64_linux_REDIR_FOR_vgetcpu), .-.LfnB4

/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple strlen implementation (written in C and compiled by gcc.)
*/
.global VG_(amd64_linux_REDIR_FOR_strlen)
.type   VG_(amd64_linux_REDIR_FOR_strlen), @function
VG_(amd64_linux_REDIR_FOR_strlen):
.LfnB5:
	xorl	%eax, %eax
	cmpb	$0, (%rdi)
	movq	%rdi, %rdx
	je	.L41
.L40:	addq	$1, %rdx
	cmpb	$0, (%rdx)
	jne	.L40
	movq	%rdx, %rax
	subq	%rdi, %rax
.L41:	ret
.LfnE5:
.size VG_(amd64_linux_REDIR_FOR_strlen), .-VG_(amd64_linux_REDIR_FOR_strlen)

.global VG_(amd64_linux_REDIR_FOR_index)
.type   VG_(amd64_linux_REDIR_FOR_index), @function
VG_(amd64_linux_REDIR_FOR_index):
        movzbl  (%rdi), %eax
        movl    %esi, %edx
        cmpb    %sil, %al
        jne     .L4
        jmp     .L5
.L10:
        addq    $1, %rdi
        movzbl  (%rdi), %eax
        cmpb    %dl, %al
        je      .L5
.L4:
        testb   %al, %al
        jne     .L10
        xorl    %eax, %eax
        ret
.L5:
        movq    %rdi, %rax
        ret
.size VG_(amd64_linux_REDIR_FOR_index), .-VG_(amd64_linux_REDIR_FOR_index)



/* A CIE for the above four functions, followed by their FDEs */
	.section .eh_frame,"a",@progbits
.Lframe1:
        .long   .LEcie1-.LScie1
.LScie1:
        .long   0x0
        .byte   0x1
        .string "zR"
        .uleb128 0x1
        .sleb128 -8
        .byte   0x10
        .uleb128 0x1
        .byte   0x3
        .byte   0xc
        .uleb128 0x7
        .uleb128 0x8
        .byte   0x90
        .uleb128 0x1
        .align 8
.LEcie1:
.LSfde2:
        .long   .LEfde2-.LASfde2
.LASfde2:
        .long   .LASfde2-.Lframe1
        .long   .LfnB2
        .long   .LfnE2-.LfnB2
        .uleb128 0x0
        .align 8
.LEfde2:
.LSfde3:
        .long   .LEfde3-.LASfde3
.LASfde3:
        .long   .LASfde3-.Lframe1
        .long   .LfnB3
        .long   .LfnE3-.LfnB3
        .uleb128 0x0
        .align 8
.LEfde3:
.LSfde4:
        .long   .LEfde4-.LASfde4
.LASfde4:
        .long   .LASfde4-.Lframe1
        .long   .LfnB4
        .long   .LfnE4-.LfnB4
        .uleb128 0x0
        .align 8
.LEfde4:
.LSfde5:
        .long   .LEfde5-.LASfde5
.LASfde5:
        .long   .LASfde5-.Lframe1
        .long   .LfnB5
        .long   .LfnE5-.LfnB5
        .uleb128 0x0
        .align 8
.LEfde5:
	.previous

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------- ppc32-linux ----------------*/
#else
#if defined(VGP_ppc32_linux)

#	define UD2_16     trap ; trap ; trap; trap
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(ppc32_linux_SUBST_FOR_sigreturn)
VG_(ppc32_linux_SUBST_FOR_sigreturn):
	li 0,__NR_sigreturn
        sc
        .long 0	/*illegal insn*/

.global VG_(ppc32_linux_SUBST_FOR_rt_sigreturn)
VG_(ppc32_linux_SUBST_FOR_rt_sigreturn):
	li 0,__NR_rt_sigreturn
        sc
        .long 0	/*illegal insn*/
	
/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple strlen implementation (written in C and compiled by gcc.)
*/
.global VG_(ppc32_linux_REDIR_FOR_strlen)
.type   VG_(ppc32_linux_REDIR_FOR_strlen), @function
VG_(ppc32_linux_REDIR_FOR_strlen):
        lbz 4,0(3)
        li 9,0
        cmpwi 0,4,0
        beq- 0,.L18
.L19:
        lbzu 5,1(3)
        addi 9,9,1
        cmpwi 0,5,0
        bne+ 0,.L19
.L18:
        mr 3,9
        blr
.size VG_(ppc32_linux_REDIR_FOR_strlen), .-VG_(ppc32_linux_REDIR_FOR_strlen)

/* Ditto strcmp */
.global VG_(ppc32_linux_REDIR_FOR_strcmp)
.type   VG_(ppc32_linux_REDIR_FOR_strcmp), @function
VG_(ppc32_linux_REDIR_FOR_strcmp):
.L20:
        lbz 0,0(3)
        cmpwi 7,0,0
        bne- 7,.L21
        lbz 0,0(4)
        li 11,0
        cmpwi 7,0,0
        beq- 7,.L22
.L21:
        lbz 0,0(3)
        li 11,-1
        cmpwi 7,0,0
        beq- 7,.L22
        lbz 0,0(4)
        li 11,1
        cmpwi 7,0,0
        beq- 7,.L22
        lbz 9,0(3)
        lbz 0,0(4)
        li 11,-1
        cmplw 7,9,0
        blt- 7,.L22
        lbz 9,0(3)
        lbz 0,0(4)
        li 11,1
        addi 3,3,1
        addi 4,4,1
        cmplw 7,9,0
        ble+ 7,.L20
.L22:
        mr 3,11
        blr
.size VG_(ppc32_linux_REDIR_FOR_strcmp), .-VG_(ppc32_linux_REDIR_FOR_strcmp)

/* Ditto index/strchr */
.global VG_(ppc32_linux_REDIR_FOR_strchr)
.type   VG_(ppc32_linux_REDIR_FOR_strchr), @function
VG_(ppc32_linux_REDIR_FOR_strchr):
        lbz 0,0(3)
        rlwinm 4,4,0,0xff
        cmpw 7,4,0
        beqlr 7
        cmpwi 7,0,0
        bne 7,.L308
        b .L304
.L309:	
        beq 6,.L304
.L308:	
        lbzu 0,1(3)
        cmpw 7,4,0
        cmpwi 6,0,0
        bne 7,.L309
        blr
.L304:	
        li 3,0
        blr
.size   VG_(ppc32_linux_REDIR_FOR_strchr),.-VG_(ppc32_linux_REDIR_FOR_strchr)
	
.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------- ppc64-linux ----------------*/
#else
#if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)

#	define UD2_16     trap ; trap ; trap; trap
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(ppc64_linux_SUBST_FOR_rt_sigreturn)
VG_(ppc64_linux_SUBST_FOR_rt_sigreturn):
	li 0,__NR_rt_sigreturn
        sc
        .long 0	/*illegal insn*/

	/* See comment in pub_core_trampoline.h for what this is for */
.global VG_(ppctoc_magic_redirect_return_stub)
VG_(ppctoc_magic_redirect_return_stub):
	trap

	/* this function is written using the "dotless" ABI convention */
	.align 2
	.globl VG_(ppc64_linux_REDIR_FOR_strlen)
#if !defined VGP_ppc64be_linux || _CALL_ELF == 2
        /* Little Endian uses ELF version 2 */
        .type VG_(ppc64_linux_REDIR_FOR_strlen),@function
VG_(ppc64_linux_REDIR_FOR_strlen):
#else
        /* Big Endian uses ELF version 1 */
	.section        ".opd","aw"
	.align 3
VG_(ppc64_linux_REDIR_FOR_strlen):
	.quad   .L.VG_(ppc64_linux_REDIR_FOR_strlen),.TOC.@tocbase,0
	.previous
	.size	VG_(ppc64_linux_REDIR_FOR_strlen), \
			.L0end-.L.VG_(ppc64_linux_REDIR_FOR_strlen)
	.type	VG_(ppc64_linux_REDIR_FOR_strlen), @function

.L.VG_(ppc64_linux_REDIR_FOR_strlen):
#endif
#if _CALL_ELF == 2
0:      addis        2,12,.TOC.-0b@ha
        addi         2,2,.TOC.-0b@l
        .localentry  VG_(ppc64_linux_REDIR_FOR_strlen), .-VG_(ppc64_linux_REDIR_FOR_strlen)
#endif
        mr 9,3
        lbz 0,0(3)
        li 3,0
        cmpwi 7,0,0
        beqlr 7
        li 3,0
.L01:
        addi 0,3,1
        extsw 3,0
        lbzx 0,9,3
        cmpwi 7,0,0
        bne 7,.L01
        blr

#if !defined VGP_ppc64be_linux || _CALL_ELF == 2
        .size VG_(ppc64_linux_REDIR_FOR_strlen),.-VG_(ppc64_linux_REDIR_FOR_strlen)
#else
        .size VG_(ppc64_linux_REDIR_FOR_strlen),.-.L.VG_(ppc64_linux_REDIR_FOR_strlen)
#endif
        .long 0
        .byte 0,0,0,0,0,0,0,0
.L0end:

        /* this function is written using the "dotless" ABI convention */
        .align 2
        .globl VG_(ppc64_linux_REDIR_FOR_strchr)
#if !defined VGP_ppc64be_linux || _CALL_ELF == 2
        .type   VG_(ppc64_linux_REDIR_FOR_strchr),@function
VG_(ppc64_linux_REDIR_FOR_strchr):
#else
	.section        ".opd","aw"
	.align 3
VG_(ppc64_linux_REDIR_FOR_strchr):
        .quad   .L.VG_(ppc64_linux_REDIR_FOR_strchr),.TOC.@tocbase,0
        .previous
        .size   VG_(ppc64_linux_REDIR_FOR_strchr), \
                        .L1end-.L.VG_(ppc64_linux_REDIR_FOR_strchr)
        .type   VG_(ppc64_linux_REDIR_FOR_strchr),@function

.L.VG_(ppc64_linux_REDIR_FOR_strchr):
#endif
#if  _CALL_ELF == 2
0:      addis         2,12,.TOC.-0b@ha
        addi         2,2,.TOC.-0b@l
        .localentry VG_(ppc64_linux_REDIR_FOR_strchr), .-VG_(ppc64_linux_REDIR_FOR_strchr)
#endif
        lbz 0,0(3)
        rldicl 4,4,0,56
        cmpw 7,4,0
        beqlr 7
        cmpdi 7,0,0
        bne 7,.L18
        b .L14
#if !defined VGP_ppc64be_linux || _CALL_ELF == 2
        .size VG_(ppc64_linux_REDIR_FOR_strchr),.-VG_(ppc64_linux_REDIR_FOR_strchr)
#else
        .size VG_(ppc64_linux_REDIR_FOR_strchr),.-.L.VG_(ppc64_linux_REDIR_FOR_strchr)
#endif
.L19:	
        beq 6,.L14
.L18:	
        lbzu 0,1(3)
        cmpw 7,4,0
        cmpdi 6,0,0
        bne 7,.L19
        blr
.L14:	
        li 3,0
        blr
        .long 0
        .byte 0,0,0,0,0,0,0,0
.L1end:

	
.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------- arm-linux ----------------*/
#else
#if defined(VGP_arm_linux)

#       define UD2_4      .word 0xFFFFFFFF
#	define UD2_16     UD2_4    ; UD2_4    ; UD2_4    ; UD2_4
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(arm_linux_SUBST_FOR_sigreturn)
.type   VG_(arm_linux_SUBST_FOR_sigreturn),#function
VG_(arm_linux_SUBST_FOR_sigreturn):
	mov r7, # __NR_sigreturn
        svc #0
        .long 0xFFFFFFFF /*illegal insn*/
.size VG_(arm_linux_SUBST_FOR_sigreturn), .-VG_(arm_linux_SUBST_FOR_sigreturn)

.global VG_(arm_linux_SUBST_FOR_rt_sigreturn)
.type   VG_(arm_linux_SUBST_FOR_rt_sigreturn),#function
VG_(arm_linux_SUBST_FOR_rt_sigreturn):
	mov r7, # __NR_rt_sigreturn
        svc #0
        .long 0xFFFFFFFF /*illegal insn*/
.size VG_(arm_linux_SUBST_FOR_rt_sigreturn), .-VG_(arm_linux_SUBST_FOR_rt_sigreturn)
	
.global VG_(arm_linux_REDIR_FOR_strlen)
VG_(arm_linux_REDIR_FOR_strlen):
	mov	r2, r0
	ldrb	r0, [r0, #0]	@ zero_extendqisi2
	@ lr needed for prologue
	cmp	r0, #0
	bxeq	lr
	mov	r0, #0
.L5:
	add	r0, r0, #1
	ldrb	r3, [r0, r2]	@ zero_extendqisi2
	cmp	r3, #0
	bne	.L5
	bx	lr
	UD2_4

.global VG_(arm_linux_REDIR_FOR_index)
VG_(arm_linux_REDIR_FOR_index):
	ldrb	r3, [r0, #0]	@ zero_extendqisi2
	and	r1, r1, #255
	cmp	r3, r1
	@ lr needed for prologue
	bne	.L9
	bx	lr
.L12:
	ldrb	r3, [r0, #1]!	@ zero_extendqisi2
	cmp	r3, r1
	beq	.L11
.L9:
	cmp	r3, #0
	bne	.L12
	mov	r0, #0
	bx	lr
.L11:
	bx	lr
	UD2_4

.global VG_(arm_linux_REDIR_FOR_memcpy)
VG_(arm_linux_REDIR_FOR_memcpy):
	stmfd	sp!, {r4, r5, lr}
	subs	lr, r2, #0
	mov	r5, r0
	beq	.L2
	cmp	r0, r1
	bls	.L4
	add	r3, r0, lr
	add	r1, lr, r1
	cmp	lr, #3
	sub	r4, r3, #1
	sub	r0, r1, #1
	ble	.L28
	sub	ip, r3, #5
	sub	r1, r1, #5
.L8:
	ldrb	r3, [r1, #4]	@ zero_extendqisi2
	sub	lr, lr, #4
	strb	r3, [ip, #4]
	ldrb	r2, [r1, #3]	@ zero_extendqisi2
	cmp	lr, #3
	strb	r2, [ip, #3]
	ldrb	r3, [r1, #2]	@ zero_extendqisi2
	mov	r4, ip
	strb	r3, [ip, #2]
	ldrb	r2, [r1, #1]	@ zero_extendqisi2
	mov	r0, r1
	strb	r2, [ip, #1]
	sub	r1, r1, #4
	sub	ip, ip, #4
	bgt	.L8
	cmp	lr, #0
	beq	.L2
.L28:
	sub	r2, lr, #1
.L21:
	sub	r2, r2, #1
	ldrb	r3, [r0], #-1	@ zero_extendqisi2
	cmn	r2, #1
	strb	r3, [r4], #-1
	bne	.L21
.L2:
	mov	r0, r5
	ldmfd	sp!, {r4, r5, pc}
.L4:
	bcs	.L2
	cmp	lr, #3
	mov	ip, r0
	ble	.L29
.L19:
	ldrb	r3, [r1, #0]	@ zero_extendqisi2
	sub	lr, lr, #4
	strb	r3, [ip, #0]
	ldrb	r2, [r1, #1]	@ zero_extendqisi2
	cmp	lr, #3
	strb	r2, [ip, #1]
	ldrb	r3, [r1, #2]	@ zero_extendqisi2
	strb	r3, [ip, #2]
	ldrb	r2, [r1, #3]	@ zero_extendqisi2
	add	r1, r1, #4
	strb	r2, [ip, #3]
	add	ip, ip, #4
	bgt	.L19
	cmp	lr, #0
	beq	.L2
.L29:
	sub	r2, lr, #1
.L20:
	sub	r2, r2, #1
	ldrb	r3, [r1], #1	@ zero_extendqisi2
	cmn	r2, #1
	strb	r3, [ip], #1
	bne	.L20
	mov	r0, r5
	ldmfd	sp!, {r4, r5, pc}
	UD2_4

.global VG_(arm_linux_REDIR_FOR_strcmp)
VG_(arm_linux_REDIR_FOR_strcmp):
.L64:
	ldrb	r3, [r0], #1	@ zero_extendqisi2
	ldrb	r2, [r1], #1	@ zero_extendqisi2
	cmp	r3, #0
	beq	.L67
	cmp	r3, r2
	beq	.L64
	rsb	r0, r2, r3
	bx	lr
.L67:
	rsb	r0, r2, #0
	bx	lr
	UD2_4

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_4
#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE
        
/*---------------- arm64-linux ----------------*/
#else
#if defined(VGP_arm64_linux)

#       define UD2_4      .word 0xFFFFFFFF
#	define UD2_16     UD2_4    ; UD2_4    ; UD2_4    ; UD2_4
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(arm64_linux_SUBST_FOR_rt_sigreturn)
.type   VG_(arm64_linux_SUBST_FOR_rt_sigreturn),#function
VG_(arm64_linux_SUBST_FOR_rt_sigreturn):
	mov x8, # __NR_rt_sigreturn
        svc #0
        .long 0xFFFFFFFF /*illegal insn*/
.size VG_(arm64_linux_SUBST_FOR_rt_sigreturn), \
        .-VG_(arm64_linux_SUBST_FOR_rt_sigreturn)

.global VG_(arm64_linux_REDIR_FOR_strlen)
.type   VG_(arm64_linux_REDIR_FOR_strlen),#function
VG_(arm64_linux_REDIR_FOR_strlen):
	mov	x2, x0
	ldrb	w0, [x0]
	cbz	w0, .L5
	mov	x0, 0
.L4:
	add	x0, x0, 1
	ldrb	w1, [x2,x0]
	cbnz	w1, .L4
	ret
.L5:
	mov	x0, 0
	ret
.size VG_(arm64_linux_REDIR_FOR_strlen), .-VG_(arm64_linux_REDIR_FOR_strlen)

.global VG_(arm64_linux_REDIR_FOR_index)
.type   VG_(arm64_linux_REDIR_FOR_index),#function
VG_(arm64_linux_REDIR_FOR_index):
        ldrb    w2, [x0]
        uxtb    w1, w1
        cmp     w2, w1
        beq     .L11
.L13:
        cbz     w2, .L16
        ldrb    w2, [x0,1]!
        cmp     w2, w1
        bne     .L13
.L11:
        ret
.L16:
        mov     x0, 0
        ret
.size VG_(arm64_linux_REDIR_FOR_index), .-VG_(arm64_linux_REDIR_FOR_index)

.global VG_(arm64_linux_REDIR_FOR_strcmp)
.type   VG_(arm64_linux_REDIR_FOR_strcmp),#function
VG_(arm64_linux_REDIR_FOR_strcmp):
        ldrb    w2, [x0]
        ldrb    w3, [x1]
        cmp     w2, w3
        bcc     .L22
.L21:
        bhi     .L25
        cbz     w2, .L26
        ldrb    w2, [x0,1]!
        ldrb    w3, [x1,1]!
        cmp     w2, w3
        bcs     .L21
.L22:
        mov     x0, -1
        ret
.L25:
        mov     x0, 1
        ret
.L26:
        mov     x0, 0
        ret
.size VG_(arm64_linux_REDIR_FOR_strcmp), .-VG_(arm64_linux_REDIR_FOR_strcmp)

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_4
#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE
        
/*---------------- x86-freebsd ----------------*/
#else
#if defined(VGP_x86_freebsd)

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(x86_freebsd_SUBST_FOR_sigreturn)
VG_(x86_freebsd_SUBST_FOR_sigreturn):
	/*
	 * PJF this magic number is fairly flakey
	 * If ever it is wrong sys_fake_sigreturn will fail
	 * the sigreturn will be to some bogus EIP address and
	 * the client will likely terminate with a SIGILL
	 * In this case adding some printfs to sigframe_create
	 * and sys_fake_sigreturn should help debugging to
	 * find the right offset
	 */
	lea	0x1c(%esp), %eax	/* args to sigreturn(ucontext_t *) */
	pushl	%eax
	pushl	%eax			/* fake return addr */
/*	movl	0x44(%eax), %gs	; restore %gs, not done by sigreturn */
        movl    $__NR_fake_sigreturn, %eax
        int     $0x80
        ud2

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

#else
#if defined(VGP_amd64_freebsd)

#	define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024

	/* a leading page of unexecutable code */
	UD2_PAGE

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(amd64_freebsd_SUBST_FOR_sigreturn)
VG_(amd64_freebsd_SUBST_FOR_sigreturn):
        /* This is a very specific sequence which GDB uses to
           recognize signal handler frames. */

        movq    $__NR_fake_sigreturn, %rax

        /* running the preprocessor on
         * src/amd64.amd64/lib/libc/sigreturn.S
         * gives
         * .text; .p2align 4,0x90; .globl __sys_sigreturn;
         * .type __sys_sigreturn,@function; __sys_sigreturn:;
         * .cfi_startproc; .weak sigreturn; .equ sigreturn,__sys_sigreturn;
         *  .weak _sigreturn; .equ _sigreturn,__sys_sigreturn;
         *  mov $417,%eax;
         * movq %rcx, %r10;
         * syscall; jb .cerror; ret; .size __sys_sigreturn, . - __sys_sigreturn;
         *  .cfi_endproc
         */

        /*
         * sigframe in sigframe-amd64-freebsd.c
         * differs from sigframe in /usr/include/x86/sigframe.h
         * by having the address to this trampoline first
         * so I assume that the +8 is to get back to the
         * FreeBSD sigframe
         */
        movq	%rsp, %rdi
        addq	$8,%rdi
        syscall
        ud2

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

	/* and a trailing page of unexecutable code */
	UD2_PAGE

#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------- x86-darwin ----------------*/
#else
#if defined(VGP_x86_darwin)

        /* a leading page of unexecutable code */
.fill 2048, 2, 0x0b0f /* `ud2` */

.globl VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.globl VG_(x86_darwin_SUBST_FOR_sigreturn)
VG_(x86_darwin_SUBST_FOR_sigreturn):
        /* XXX does this need to have any special form? (cf x86-linux
	version) */
        movl    $ __NR_DARWIN_FAKE_SIGRETURN, %eax
        int     $0x80
        ud2

.globl VG_(x86_darwin_REDIR_FOR_strlen)
VG_(x86_darwin_REDIR_FOR_strlen):
        movl    4(%esp), %edx
        movl    %edx, %eax
        jmp     1f
0:
        incl    %eax
1:
        cmpb    $0, (%eax)
        jne     0b
        subl    %edx, %eax
        ret

.globl VG_(x86_darwin_REDIR_FOR_strcat)
VG_(x86_darwin_REDIR_FOR_strcat):
        pushl   %esi
        movl    8(%esp), %esi
        movl    12(%esp), %ecx
        movl    %esi, %edx
        jmp     1f
0:
        incl    %edx
1:
        cmpb    $0, (%edx)
        jne     0b
2:
        movzbl  (%ecx), %eax
        incl    %ecx
        movb    %al, (%edx)
        incl    %edx
        testb   %al, %al
        jne     2b
        movl    %esi, %eax
        popl    %esi
        ret


.globl VG_(x86_darwin_REDIR_FOR_strcmp)
VG_(x86_darwin_REDIR_FOR_strcmp):
        movl    4(%esp), %edx
        movl    8(%esp), %ecx
        jmp     1f
0:
        incl    %edx
        incl    %ecx
1:
        movzbl  (%edx), %eax
        testb   %al, %al
        je      2f
        cmpb    (%ecx), %al
        je      0b
2:
        movzbl  (%ecx),%edx
        movzbl  %al,%eax
        subl    %edx, %eax
        ret


.globl VG_(x86_darwin_REDIR_FOR_strcpy)
VG_(x86_darwin_REDIR_FOR_strcpy):
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%esi
	movl	8(%ebp), %esi
	movl	12(%ebp), %ecx
	movl	%esi, %edx
	jmp	1f
0:
	incl	%ecx
	incl	%edx
1:
	movzbl	(%ecx), %eax
	testb	%al, %al
	movb	%al, (%edx)
	jne	0b
	movl	%esi, %eax
	popl	%esi
	leave
	ret

.globl VG_(x86_darwin_REDIR_FOR_strlcat)
VG_(x86_darwin_REDIR_FOR_strlcat):
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%edi
	pushl	%esi
	subl	$16, %esp
	movl	8(%ebp), %esi
	movl	16(%ebp), %ecx
	movl	%esi, %edx
	leal	(%ecx,%esi), %eax
	jmp	1f
0:
	incl	%edx
1:
	cmpl	%edx, %eax
	je	2f
	cmpb	$0, (%edx)
	jne	0b
2:
	movl	%edx, %edi
	subl	%esi, %edi
	movl	%ecx, %esi
	subl	%edi, %esi
	je	3f
	movl	12(%ebp), %eax
	jmp	6f
3:
	movl	12(%ebp), %eax
	movl	%eax, (%esp)
	call	VG_(x86_darwin_REDIR_FOR_strlen)
	jmp	7f
4:
	cmpl	$1, %esi
	je	5f
	movb	%cl, (%edx)
	decl	%esi
	incl	%edx
5:
	incl	%eax
6:
	movzbl	(%eax), %ecx
	testb	%cl, %cl
	jne	4b
	movb	$0, (%edx)
	subl	12(%ebp), %eax
7:
	addl	$16, %esp
	leal	(%edi,%eax), %eax
	popl	%esi
	popl	%edi
	leave
	ret
	
	
.globl VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

        /* a trailing page of unexecutable code */
.fill 2048, 2, 0x0b0f /* `ud2` */


/*---------------- amd64-darwin ----------------*/
#else
#if defined(VGP_amd64_darwin)

        /* a leading page of unexecutable code */
.fill 2048, 2, 0x0b0f /* `ud2` */

.globl VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.globl VG_(amd64_darwin_SUBST_FOR_sigreturn)
VG_(amd64_darwin_SUBST_FOR_sigreturn):
        /* XXX does this need to have any special form? (cf x86-linux
	version) */
        movq    $ __NR_DARWIN_FAKE_SIGRETURN, %rax
        syscall
        ud2

.globl VG_(amd64_darwin_REDIR_FOR_strlen)
VG_(amd64_darwin_REDIR_FOR_strlen):
        movq    %rdi, %rax
        jmp     1f
0:
        incq    %rax
1:
        cmpb    $0, (%rax)
        jne     0b
        subq    %rdi, %rax
        ret

.globl VG_(amd64_darwin_REDIR_FOR_strcat)
VG_(amd64_darwin_REDIR_FOR_strcat):
	movq	%rdi, %rdx
	jmp	1f
0:
	incq	%rdx
1:
	cmpb	$0, (%rdx)
	jne	0b
2:
	movzbl	(%rsi), %eax
	incq	%rsi
	movb	%al, (%rdx)
	incq	%rdx
	testb	%al, %al
	jne	2b
	movq	%rdi, %rax
	ret


.globl VG_(amd64_darwin_REDIR_FOR_strcmp)
VG_(amd64_darwin_REDIR_FOR_strcmp):
	jmp	1f
0:
	incq	%rdi
	incq	%rsi
1:
	movzbl	(%rdi), %eax
	testb	%al, %al
	je	2f
	cmpb	(%rsi), %al
	je	0b
2:
	movzbl	(%rsi), %edx
	movzbl	%al, %eax
	subl	%edx, %eax
	ret

.globl VG_(amd64_darwin_REDIR_FOR_strcpy)
VG_(amd64_darwin_REDIR_FOR_strcpy):
	pushq	%rbp
	movq	%rdi, %rdx
	movq	%rsp, %rbp
	jmp	1f
0:
	incq	%rsi
	incq	%rdx
1:
	movzbl	(%rsi), %eax
	testb	%al, %al
	movb	%al, (%rdx)
	jne	0b
	leave
	movq	%rdi, %rax
	ret
	
.globl VG_(amd64_darwin_REDIR_FOR_strlcat)
VG_(amd64_darwin_REDIR_FOR_strlcat):
	pushq	%rbp
	leaq	(%rdx,%rdi), %rax
	movq	%rdi, %rcx
	movq	%rsp, %rbp
	pushq	%rbx
	subq	$8, %rsp
	jmp	1f
0:
	incq	%rcx
1:
	cmpq	%rcx, %rax
	je	2f
	cmpb	$0, (%rcx)
	jne	0b
2:
	movq	%rcx, %rbx
	subq	%rdi, %rbx
	movq	%rdx, %rdi
	subq	%rbx, %rdi
	je	3f
	movq	%rsi, %rax
	jmp	6f
3:
	movq	%rsi, %rdi
	call	VG_(amd64_darwin_REDIR_FOR_strlen)
	jmp	7f
4:
	cmpq	$1, %rdi
	je	5f
	movb	%dl, (%rcx)
	decq	%rdi
	incq	%rcx
5:
	incq	%rax
6:
	movzbl	(%rax), %edx
	testb	%dl, %dl
	jne	4b
	movb	$0, (%rcx)
	subq	%rsi, %rax
7:
	leaq	(%rbx,%rax), %rax
	addq	$8, %rsp
	popq	%rbx
	leave
	ret

.globl VG_(amd64_darwin_REDIR_FOR_arc4random)
VG_(amd64_darwin_REDIR_FOR_arc4random):
	/* not very random, hope dyld won't mind */
	movq	$0x76616c6772696e64, %rax
	ret

.globl VG_(amd64_darwin_REDIR_FOR_strchr)
VG_(amd64_darwin_REDIR_FOR_strchr):
        pushq   %rbp
        movq    %rsp, %rbp
        movb    (%rdi), %cl
        cmpb    %sil, %cl
        jne     1f
        movq    %rdi, %rax
        popq    %rbp
        ret
1:
        testb   %cl, %cl
        movl    $0, %eax
        je      2f
        movb    1(%rdi), %cl
        incq    %rdi
        cmpb    %sil, %cl
        movq    %rdi, %rax
        jne     1b
2:
        popq    %rbp
        ret
        
.globl VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

        /* a trailing page of unexecutable code */
.fill 2048, 2, 0x0b0f /* `ud2` */


/*---------------- s390x-linux ----------------*/
#else
#if defined(VGP_s390x_linux)

        /* a leading page of unexecutable code */
	.fill 2048, 2, 0x0000

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(s390x_linux_SUBST_FOR_sigreturn)
VG_(s390x_linux_SUBST_FOR_sigreturn):
        svc __NR_sigreturn
	.short 0

.global VG_(s390x_linux_SUBST_FOR_rt_sigreturn)
VG_(s390x_linux_SUBST_FOR_rt_sigreturn):
        /* Old gcc unwinding code checks for a sig(_rt)_return svc and then
           for ra = cfa to decide if it is a sig_rt_frame or not. Since we
           set ra to this trampoline, but the cfa is still in the stack,
           the unwinder thinks, that this is a non-rt frame  and causes a
           crash in the gcc unwinder - which is used by the thread library
           and others. Therefore we add a lr 1,1 nop, to let the gcc
           unwinder bail out gracefully. This might also affect unwinding
           across the signal frame - tough luck. fixs390 */
        lr 1,1
        svc __NR_rt_sigreturn
	.short 0

.global VG_(s390x_linux_REDIR_FOR_index)
.type   VG_(s390x_linux_REDIR_FOR_index),@function
VG_(s390x_linux_REDIR_FOR_index):
#
#   %r2 = address of string
#   %r3 = character to find
#
        lghi    %r0,255
        ngr     %r0,%r3        # r0 = (unsigned char)r3
        lghi    %r4,0
.L1:
        llgc    %r1,0(%r2)     # r1 = byte from string
        cr      %r1,%r0        # compare
        ber     %r14           # return if found
        cr      %r1,%r4        # end of string ?
        je      .L2
        aghi    %r2,1          # increment r2
        j       .L1
.L2:    lghi    %r2,0          # return value 0
        br      %r14
.size VG_(s390x_linux_REDIR_FOR_index), .-VG_(s390x_linux_REDIR_FOR_index)

.globl VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):
	.fill 2048, 2, 0x0000

/*---------------------- mips32-linux ----------------------*/
#else
#if defined(VGP_mips32_linux)

#	define UD2_16     trap ; trap ; trap; trap
#	define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#	define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#	define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#	define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  


.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(mips32_linux_SUBST_FOR_sigreturn)
VG_(mips32_linux_SUBST_FOR_sigreturn):
        li $v0,__NR_sigreturn
        syscall
        nop
        .long 0	/*illegal insn*/

.global VG_(mips32_linux_SUBST_FOR_rt_sigreturn)
VG_(mips32_linux_SUBST_FOR_rt_sigreturn):
	li $v0,__NR_rt_sigreturn
        syscall
        nop
        .long 0	/*illegal insn*/
	
/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple index() and strlen() implementations.
*/

.set push
.set noreorder

.global VG_(mips32_linux_REDIR_FOR_index)
.type   VG_(mips32_linux_REDIR_FOR_index), @function
VG_(mips32_linux_REDIR_FOR_index):
      move $v0, $a0
   index_loop:
      lbu $t0, 0($v0)
      beq $t0, $a1, index_end
      nop
      bne $t0, $zero, index_loop
      addiu $v0, $v0, 1
      move $v0, $zero
   index_end:
      jr $ra
      nop
.size VG_(mips32_linux_REDIR_FOR_index), .-VG_(mips32_linux_REDIR_FOR_index)

.global VG_(mips32_linux_REDIR_FOR_strlen)
.type   VG_(mips32_linux_REDIR_FOR_strlen), @function
VG_(mips32_linux_REDIR_FOR_strlen):
      move $v0, $a0
   strlen_loop:
      lbu $t0, 0($a0)
      bne $t0, $zero, strlen_loop
      addiu $a0, $a0, 1
      subu $v0, $a0, $v0
      jr $ra
      addiu $v0, $v0, -1
.size VG_(mips32_linux_REDIR_FOR_strlen), .-VG_(mips32_linux_REDIR_FOR_strlen)

.set pop

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):


#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------------- nanomips-linux --------------------*/
#else
#if defined(VGP_nanomips_linux)

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.set push
.set noreorder

.global VG_(nanomips_linux_SUBST_FOR_rt_sigreturn)
VG_(nanomips_linux_SUBST_FOR_rt_sigreturn):
   li $t4, __NR_rt_sigreturn
   syscall[32]
   .long 0

.global VG_(nanomips_linux_REDIR_FOR_index)
.type   VG_(nanomips_linux_REDIR_FOR_index), @function
VG_(nanomips_linux_REDIR_FOR_index):
   index_loop:
      lbu $t0, 0($a0)
      beqc $t0, $a1, index_end
      addiu $a0, $a0, 1
      bnec $t0, $zero, index_loop
      move $a0, $zero
   index_end:
      jrc $ra
.size VG_(nanomips_linux_REDIR_FOR_index), .-VG_(nanomips_linux_REDIR_FOR_index)

.global VG_(nanomips_linux_REDIR_FOR_strlen)
.type   VG_(nanomips_linux_REDIR_FOR_strlen), @function
VG_(nanomips_linux_REDIR_FOR_strlen):
      move $t1, $a0
   strlen_loop:
      lbu $t0, 0($a0)
      addiu $a0, $a0, 1
      bnec $t0, $zero, strlen_loop
      subu $a0, $a0, $t1
      addiu $a0, $a0, -1
      jrc $ra

.size VG_(nanomips_linux_REDIR_FOR_strlen), .-VG_(nanomips_linux_REDIR_FOR_strlen)

.set pop

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):


/*---------------------- mips64-linux ----------------------*/
#else
#if defined(VGP_mips64_linux)

#       define UD2_16     trap ; trap ; trap; trap
#       define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
#       define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
#       define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
#       define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

.global VG_(mips64_linux_SUBST_FOR_rt_sigreturn)
VG_(mips64_linux_SUBST_FOR_rt_sigreturn):
        li $2,__NR_rt_sigreturn
        syscall
        nop
        .long 0	/*illegal insn*/

/* There's no particular reason that this needs to be handwritten
   assembly, but since that's what this file contains, here's a
   simple index() and strlen() implementations.
*/

.set push
.set noreorder

.global VG_(mips64_linux_REDIR_FOR_index)
.type   VG_(mips64_linux_REDIR_FOR_index), @function
VG_(mips64_linux_REDIR_FOR_index):
      move $v0, $a0
   index_loop:
      lbu $t0, 0($v0)
      beq $t0, $a1, index_end
      nop
      bne $t0, $zero, index_loop
      daddiu $v0, $v0, 1
      move $v0, $zero
   index_end:
      jr $ra
      nop
.size VG_(mips64_linux_REDIR_FOR_index), .-VG_(mips64_linux_REDIR_FOR_index)

.global VG_(mips64_linux_REDIR_FOR_strlen)
.type   VG_(mips64_linux_REDIR_FOR_strlen), @function
VG_(mips64_linux_REDIR_FOR_strlen):
      move $v0, $a0
   strlen_loop:
      lbu $t0, 0($a0)
      bne $t0, $zero, strlen_loop
      daddiu $a0, $a0, 1
      dsubu $v0, $a0, $v0
      jr $ra
      daddiu $v0, $v0, -1
.size VG_(mips64_linux_REDIR_FOR_strlen), .-VG_(mips64_linux_REDIR_FOR_strlen)

.set pop

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):


#	undef UD2_16
#	undef UD2_64
#	undef UD2_256
#	undef UD2_1024
#	undef UD2_PAGE

/*---------------- x86-solaris ----------------*/
#else
#if defined(VGP_x86_solaris)

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

/* int strcmp(const char *s1, const char *s2); */
.global VG_(x86_solaris_REDIR_FOR_strcmp)
.type   VG_(x86_solaris_REDIR_FOR_strcmp), @function
VG_(x86_solaris_REDIR_FOR_strcmp):
        pushl   %ebp                    /* establish a stack frame */
        movl    %esp, %ebp
        movl    8(%ebp), %edx           /* get s1 */
        movl    12(%esp), %ecx          /* get s2 */
        jmp     2f                      /* go compare the first characters */
1:
        incl    %edx                    /* skip to the next s1 character */
        incl    %ecx                    /* skip to the next s2 character */
2:
        movzbl  (%edx), %eax            /* load a character from s1 */
        testb   %al, %al                /* is it null? */
        jz      3f                      /* yes, exit */
        cmpb    (%ecx), %al             /* are the characters equal? */
        je      1b                      /* yes, proceed with next characters */
3:
        movzbl  (%ecx), %edx            /* load a character from s2 */
        subl    %edx, %eax              /* calculate the return value */
        popl    %ebp                    /* destroy the stack frame */
        ret                             /* return to the caller */
.size VG_(x86_solaris_REDIR_FOR_strcmp), .-VG_(x86_solaris_REDIR_FOR_strcmp)

/* size_t strlen(const char *s); */
.global VG_(x86_solaris_REDIR_FOR_strlen)
.type   VG_(x86_solaris_REDIR_FOR_strlen), @function
VG_(x86_solaris_REDIR_FOR_strlen):
        pushl   %ebp                    /* establish a stack frame */
        movl    %esp, %ebp
        movl    8(%ebp), %edx           /* get s */
        movl    %edx, %eax              /* copy s */
        jmp     2f                      /* go handle the first character */
1:
        incl    %eax                    /* skip to the next s character */
2:
        cmpb    $0, (%eax)              /* is the s character null? */
        jne     1b                      /* no, go process the next character */
        subl    %edx, %eax              /* calculate the return value */
        popl    %ebp                    /* destroy the stack frame */
        ret                             /* return to the caller */
.size VG_(x86_solaris_REDIR_FOR_strlen), .-VG_(x86_solaris_REDIR_FOR_strlen)

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

/*---------------- amd64-solaris ----------------*/
#else
#if defined(VGP_amd64_solaris)

.global VG_(trampoline_stuff_start)
VG_(trampoline_stuff_start):

/* char *strcpy(char *restrict s1, const char *restrict s2); */
.global VG_(amd64_solaris_REDIR_FOR_strcpy)
.type   VG_(amd64_solaris_REDIR_FOR_strcpy), @function
VG_(amd64_solaris_REDIR_FOR_strcpy):
        pushq   %rbp                    /* establish a stack frame */
        movq    %rsp, %rbp
        movq    %rdi, %rdx              /* copy s1 */
1:
        movzbl  (%rsi), %eax            /* load one input character */
        movb    %al, (%rdx)             /* copy to output/s1 */
        incq    %rsi                    /* skip to the next output character */
        incq    %rdx                    /* skip to the next input character */
        testb   %al, %al                /* is the copied character null? */
        jnz     1b                      /* no, copy the next character */
        leave                           /* destroy the stack frame */
        movq    %rdi, %rax              /* set s1 as the return value */
        ret                             /* return to the caller */
.size VG_(amd64_solaris_REDIR_FOR_strcpy), .-VG_(amd64_solaris_REDIR_FOR_strcpy)

/* char *strncpy(char *restrict s1, const char *restrict s2, size_t n); */
.global VG_(amd64_solaris_REDIR_FOR_strncpy)
.type   VG_(amd64_solaris_REDIR_FOR_strncpy), @function
VG_(amd64_solaris_REDIR_FOR_strncpy):
        pushq   %rbp                    /* establish a stack frame */
        movq    %rsp, %rbp
        movq    %rdi, %rcx              /* copy s1 */
1:
        testq   %rdx, %rdx              /* is the remaining size zero? */
        jz      3f                      /* yes, all done */
        movzbl  (%rsi), %eax            /* load one input character */
        movb    %al, (%rcx)             /* copy to output/s1 */
        decq    %rdx                    /* decrement the remaining size */
        incq    %rsi                    /* skip to the next output character */
        incq    %rcx                    /* skip to the next input character */
        testb   %al, %al                /* is the copied character null? */
        jnz     1b                      /* no, copy the next character */
2:
        testq   %rdx, %rdx              /* is the remaining size zero? */
        jz      3f                      /* yes, all done */
        movb    $0, (%rdx)              /* copy null to output/s2 */
        decq    %rdx                    /* decrement the remaining size */
        incq    %rsi                    /* skip to next output character */
        jmp     2b                      /* proceed with the next character */
3:
        leave                           /* destroy the stack frame */
        movq    %rdi, %rax              /* set s1 as the return value */
        ret                             /* return to the caller */
.size VG_(amd64_solaris_REDIR_FOR_strncpy), .-VG_(amd64_solaris_REDIR_FOR_strncpy)

/* int strcmp(const char *s1, const char *s2); */
.global VG_(amd64_solaris_REDIR_FOR_strcmp)
.type   VG_(amd64_solaris_REDIR_FOR_strcmp), @function
VG_(amd64_solaris_REDIR_FOR_strcmp):
        pushq   %rbp                    /* establish a stack frame */
        movq    %rsp, %rbp
        jmp     2f                      /* go compare the first characters */
1:
        incq    %rdi                    /* skip to the next s1 character */
        incq    %rsi                    /* skip to the next s2 character */
2:
        movzbl  (%rdi), %eax            /* load a character from s1 */
        testb   %al, %al                /* is it null? */
        jz      3f                      /* yes, exit */
        cmpb    (%rsi), %al             /* are the characters equal? */
        je      1b                      /* yes, proceed with next characters */
3:
        movzbl  (%rsi), %edx            /* load a character from s2 */
        subl    %edx, %eax              /* calculate the return value */
        leave                           /* destroy the stack frame */
        ret                             /* return to the caller */
.size VG_(amd64_solaris_REDIR_FOR_strcmp), .-VG_(amd64_solaris_REDIR_FOR_strcmp)

/* char *strcat(char *restrict s1, const char *restrict s2); */
.global VG_(amd64_solaris_REDIR_FOR_strcat)
.type   VG_(amd64_solaris_REDIR_FOR_strcat), @function
VG_(amd64_solaris_REDIR_FOR_strcat):
        pushq   %rbp                    /* establish a stack frame */
        movq    %rsp, %rbp
        movq    %rdi, %rdx              /* copy s1 */
        jmp     2f                      /* go handle the first character */
1:
        incq    %rdx                    /* skip to the next s1 character */
2:
        cmpb    $0, (%rdx)              /* is the s1 character null? */
        jne     1b                      /* no, go check the next character */
3:
        movzbl  (%rsi), %eax            /* load a character from s2 */
        movb    %al, (%rdx)             /* copy the s2 character to s1 */
        incq    %rdx                    /* skip to the next s1 character */
        incq    %rsi                    /* skip to the next s2 character */
        testb   %al, %al                /* was the character null? */
        jnz     3b                      /* no, go copy the next character */
        movq    %rdi, %rax              /* set s1 as the return value */
        leave                           /* destroy the stack frame */
        ret                             /* return to the caller */
.size VG_(amd64_solaris_REDIR_FOR_strcat), .-VG_(amd64_solaris_REDIR_FOR_strcat)

/* size_t strlen(const char *s); */
.global VG_(amd64_solaris_REDIR_FOR_strlen)
.type   VG_(amd64_solaris_REDIR_FOR_strlen), @function
VG_(amd64_solaris_REDIR_FOR_strlen):
        pushq   %rbp                    /* establish a stack frame */
        movq    %rsp, %rbp
        movq    %rdi, %rax              /* copy s */
        jmp     2f                      /* go handle the first character */
1:
        incq    %rax                    /* skip to the next s character */
2:
        cmpb    $0, (%rax)              /* is the s character null? */
        jne     1b                      /* no, go process the next character */
        subq    %rdi, %rax              /* calculate the return value */
        leave                           /* destroy the stack frame */
        ret                             /* return to the caller */
.size VG_(amd64_solaris_REDIR_FOR_strlen), .-VG_(amd64_solaris_REDIR_FOR_strlen)

.global VG_(trampoline_stuff_end)
VG_(trampoline_stuff_end):

/*---------------- unknown ----------------*/
#else
#  error Unknown platform

#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif

/* Let the linker know we don't need an executable stack */
MARK_STACK_NO_EXEC

/*--------------------------------------------------------------------*/
/*--- end                                                          ---*/
/*--------------------------------------------------------------------*/
