1141963Swpaul/*- 2141963Swpaul * Copyright (c) 2005 3141963Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4141963Swpaul * 5141963Swpaul * Redistribution and use in source and binary forms, with or without 6141963Swpaul * modification, are permitted provided that the following conditions 7141963Swpaul * are met: 8141963Swpaul * 1. Redistributions of source code must retain the above copyright 9141963Swpaul * notice, this list of conditions and the following disclaimer. 10141963Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11141963Swpaul * notice, this list of conditions and the following disclaimer in the 12141963Swpaul * documentation and/or other materials provided with the distribution. 13141963Swpaul * 3. All advertising materials mentioning features or use of this software 14141963Swpaul * must display the following acknowledgement: 15141963Swpaul * This product includes software developed by Bill Paul. 16141963Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17141963Swpaul * may be used to endorse or promote products derived from this software 18141963Swpaul * without specific prior written permission. 19141963Swpaul * 20141963Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21141963Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22141963Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23141963Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24141963Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25141963Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26141963Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27141963Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28141963Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29141963Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30141963Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31141963Swpaul * 32141963Swpaul * The x86_64 callback routines were written and graciously submitted 33141963Swpaul * by Ville-Pertti Keinonen <will@exomi.com>. 34141963Swpaul * 35141963Swpaul * $FreeBSD$ 36141963Swpaul */ 37141963Swpaul 38141963Swpaul#include <machine/asmacros.h> 39141963Swpaul 40141963Swpaul/* 41141963Swpaul * Wrapper for handling up to 16 arguments. We can't really 42141963Swpaul * know how many arguments the caller will pass us. I'm taking an 43141963Swpaul * educated guess that we'll never get over 16. Handling too 44141963Swpaul * few arguments is bad. Handling too many is inefficient, but 45141963Swpaul * not fatal. If someone can think of a way to handle an arbitrary 46141963Swpaul * number of arguments with more elegant code, freel free to let 47141963Swpaul * me know. 48141963Swpaul * 49141963Swpaul * Standard amd64 calling conventions specify the following registers 50141963Swpaul * to be used for passing the first 6 arguments: 51141963Swpaul * 52141963Swpaul * %rdi, %rsi, %rdx, %rcx, %r8, %r9 53141963Swpaul * 54141963Swpaul * Further arguments are passed on the stack (the 7th argument is 55141963Swpaul * located immediately after the return address). 56141963Swpaul * 57141963Swpaul * Windows x86_64 calling conventions only pass the first 4 58141963Swpaul * arguments in registers: 59141963Swpaul * 60141963Swpaul * %rcx, %rdx, %r8, %r9 61141963Swpaul * 62141963Swpaul * Even when arguments are passed in registers, the stack must have 63141963Swpaul * space reserved for those arguments. Thus the 5th argument (the 64141963Swpaul * first non-register argument) is placed 32 bytes after the return 65141963Swpaul * address. Additionally, %rdi and %rsi must be preserved. (These 66141963Swpaul * two registers are not scratch registers in the standard convention.) 67141963Swpaul * 68141963Swpaul * Note that in this template, we load a contrived 64 bit address into 69141963Swpaul * %r11 to represent our jump address. This is to guarantee that the 70141963Swpaul * assembler leaves enough room to patch in an absolute 64-bit address 71141963Swpaul * later. The idea behind this code is that we want to avoid having to 72141963Swpaul * manually create all the wrapper functions at compile time with 73141963Swpaul * a bunch of macros. This is doable, but a) messy and b) requires 74141963Swpaul * us to maintain two separate tables (one for the UNIX function 75141963Swpaul * pointers and another with the wrappers). This means I'd have to 76141963Swpaul * update two different tables each time I added a function. 77141963Swpaul * 78141963Swpaul * To avoid this, we create the wrappers at runtime instead. The 79141963Swpaul * image patch tables now contain two pointers: one two the normal 80141963Swpaul * routine, and a blank one for the wrapper. To construct a wrapper, 81141963Swpaul * we allocate some memory and copy the template function into it, 82141963Swpaul * then patch the function pointer for the routine we want to wrap 83141963Swpaul * into the newly created wrapper. The subr_pe module can then 84141963Swpaul * simply patch the wrapper routine into the jump table into the 85141963Swpaul * windows image. As a bonus, the wrapper pointer not only serves 86141963Swpaul * as the wrapper entry point address, it's also a data pointer 87141963Swpaul * that we can pass to free() later when we unload the module. 88141963Swpaul */ 89141963Swpaul 90141963Swpaul .globl x86_64_wrap_call 91141963Swpaul .globl x86_64_wrap_end 92141963Swpaul 93141963SwpaulENTRY(x86_64_wrap) 94145133Swpaul push %rbp # insure that the stack 95145133Swpaul mov %rsp,%rbp # is 16-byte aligned 96145133Swpaul and $-16,%rsp # 97142035Swpaul subq $96,%rsp # allocate space on stack 98142035Swpaul mov %rsi,96-8(%rsp) # save %rsi 99142035Swpaul mov %rdi,96-16(%rsp)# save %rdi 100142035Swpaul mov %rcx,%r10 # temporarily save %rcx in scratch 101145133Swpaul lea 56+8(%rbp),%rsi # source == old stack top (stack+56) 102142035Swpaul mov %rsp,%rdi # destination == new stack top 103142035Swpaul mov $10,%rcx # count == 10 quadwords 104142035Swpaul rep 105142035Swpaul movsq # copy old stack contents to new location 106142035Swpaul mov %r10,%rdi # set up arg0 (%rcx -> %rdi) 107142035Swpaul mov %rdx,%rsi # set up arg1 (%rdx -> %rsi) 108142035Swpaul mov %r8,%rdx # set up arg2 (%r8 -> %rdx) 109142035Swpaul mov %r9,%rcx # set up arg3 (%r9 -> %rcx) 110145133Swpaul mov 40+8(%rbp),%r8 # set up arg4 (stack+40 -> %r8) 111145133Swpaul mov 48+8(%rbp),%r9 # set up arg5 (stack+48 -> %r9) 112142035Swpaul xor %rax,%rax # clear return value 113141963Swpaulx86_64_wrap_call: 114141963Swpaul mov $0xFF00FF00FF00FF00,%r11 115142035Swpaul callq *%r11 # call routine 116142035Swpaul mov 96-16(%rsp),%rdi# restore %rdi 117142035Swpaul mov 96-8(%rsp),%rsi # restore %rsi 118145133Swpaul leave # delete space on stack 119141963Swpaul ret 120141963Swpaulx86_64_wrap_end: 121141963Swpaul 122141963Swpaul/* 123141963Swpaul * Functions for invoking x86_64 callbacks. In each case, the first 124141963Swpaul * argument is a pointer to the function. 125141963Swpaul */ 126141963Swpaul 127141963SwpaulENTRY(x86_64_call1) 128215708Sbschmidt subq $40,%rsp 129141963Swpaul mov %rsi,%rcx 130141963Swpaul call *%rdi 131215708Sbschmidt addq $40,%rsp 132141963Swpaul ret 133141963Swpaul 134141963SwpaulENTRY(x86_64_call2) 135215708Sbschmidt subq $40,%rsp 136141963Swpaul mov %rsi,%rcx 137141963Swpaul /* %rdx is already correct */ 138141963Swpaul call *%rdi 139215708Sbschmidt addq $40,%rsp 140141963Swpaul ret 141141963Swpaul 142141963SwpaulENTRY(x86_64_call3) 143215708Sbschmidt subq $40,%rsp 144141963Swpaul mov %rcx,%r8 145141963Swpaul mov %rsi,%rcx 146141963Swpaul call *%rdi 147215708Sbschmidt addq $40,%rsp 148141963Swpaul ret 149141963Swpaul 150141963SwpaulENTRY(x86_64_call4) 151141963Swpaul subq $40,%rsp 152141963Swpaul mov %r8,%r9 153141963Swpaul mov %rcx,%r8 154141963Swpaul mov %rsi,%rcx 155141963Swpaul call *%rdi 156141963Swpaul addq $40,%rsp 157141963Swpaul ret 158141963Swpaul 159141963SwpaulENTRY(x86_64_call5) 160215708Sbschmidt subq $48,%rsp 161141963Swpaul mov %r9,32(%rsp) 162141963Swpaul mov %r8,%r9 163141963Swpaul mov %rcx,%r8 164141963Swpaul mov %rsi,%rcx 165141963Swpaul call *%rdi 166215708Sbschmidt addq $48,%rsp 167141963Swpaul ret 168141963Swpaul 169141963SwpaulENTRY(x86_64_call6) 170141963Swpaul subq $56,%rsp 171141963Swpaul mov 56+8(%rsp),%rax 172141963Swpaul mov %r9,32(%rsp) 173141963Swpaul mov %rax,40(%rsp) 174141963Swpaul mov %r8,%r9 175141963Swpaul mov %rcx,%r8 176141963Swpaul mov %rsi,%rcx 177141963Swpaul call *%rdi 178141963Swpaul addq $56,%rsp 179141963Swpaul ret 180