| |
| /*--------------------------------------------------------------------*/ |
| /*--- Trampoline code page stuff. m_trampoline.S ---*/ |
| /*--------------------------------------------------------------------*/ |
| |
| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2000-2012 Julian Seward |
| jseward@acm.org |
| Copyright (C) 2006-2012 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, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| 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) |
| |
| |
| /* 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_ppc64_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) |
| .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): |
| 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 |
| .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) |
| .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): |
| lbz 0,0(3) |
| rldicl 4,4,0,56 |
| cmpw 7,4,0 |
| beqlr 7 |
| cmpdi 7,0,0 |
| bne 7,.L18 |
| b .L14 |
| .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 |
| |
| /*---------------- ppc32-linux ----------------*/ |
| |
| #elif 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_(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-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_(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 |
| |
| .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 strlen implementation (written in C and compiled by gcc.) |
| */ |
| .global VG_(mips32_linux_REDIR_FOR_strlen) |
| .type VG_(mips32_linux_REDIR_FOR_strlen), @function |
| VG_(mips32_linux_REDIR_FOR_strlen): |
| li $v0, 0 |
| //la $a0, string |
| j strlen_cond |
| strlen_loop: |
| addi $v0, $v0, 1 |
| addi $a0, $a0, 1 |
| strlen_cond: |
| lbu $t0, ($a0) |
| bne $t0, $zero, strlen_loop |
| jr $ra |
| |
| .size VG_(mips32_linux_REDIR_FOR_strlen), .-VG_(mips32_linux_REDIR_FOR_strlen) |
| |
| .global VG_(trampoline_stuff_end) |
| VG_(trampoline_stuff_end): |
| |
| |
| # undef UD2_16 |
| # undef UD2_64 |
| # undef UD2_256 |
| # undef UD2_1024 |
| # undef UD2_PAGE |
| |
| /*---------------- unknown ----------------*/ |
| #else |
| # error Unknown platform |
| |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| #endif |
| |
| #if defined(VGO_linux) |
| /* Let the linker know we don't need an executable stack */ |
| # if defined(VGP_arm_linux) |
| .section .note.GNU-stack,"",%progbits |
| # else |
| .section .note.GNU-stack,"",@progbits |
| # endif |
| #endif |
| |
| /*--------------------------------------------------------------------*/ |
| /*--- end ---*/ |
| /*--------------------------------------------------------------------*/ |