Mercurial > pub > dyncall > dyncall
diff dyncall/dyncall_call_x86_8a.s @ 0:3e629dc19168
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:24:28 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncall/dyncall_call_x86_8a.s Thu Mar 19 22:24:28 2015 +0100 @@ -0,0 +1,127 @@ +/* + + Package: dyncall + Library: dyncall + File: dyncall/dyncall_call_x86_8a.s + Description: All x86 abi call kernel implementations in Plan9's assembler + License: + + Copyright (c) 2007-2011 Daniel Adler <dadler@uni-goettingen.de>, + Tassilo Philipp <tphilipp@potion-studios.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + + +/* 64 bit integer return value calls require caller to create space for return + value, and pass a pointer to it as 1st argument. This main function handles + all cases (32 and 64 bit integers, as well as floats and doubles), however, + it has to be called through the 2 corresponding functions at the end of + this file. + In order to keep things simple, we basically put the pointer to the + return value in EDX and call the other assembler code, above. If EDX + is not null, then the code below will push it to the stack as first + argument. +*/ + +call_main: + + /* Since all registers except SP are scratch, and we have a variable + argument size depending on the function to call, we have to find + a way to store and restore SP. + The idea is to replace the return address with a custom one on the + stack, and to put some logic there, jumping back to the real + return address. This allows us, to put the SP somewhere next to + the fake return address on the stack, so that we can get it back + with a fixed offset (relative to the program counter, in our case). + + The only real issue with this approach would be a non-executable + stack. However, Plan9 doesn't support w^x at the time of writing. + */ + + /* On the stack at this point: + RETADDR 0(SP) + FUNPTR 4(SP) + ARGS 8(SP) + SIZE 12(SP) + */ + + MOVL SP, BP /* base pointer for convenience */ + PUSHL SP /* save stack pointer */ + + MOVL 8(BP), SI /* SI = pointer on args */ + MOVL 12(BP), CX /* CX = size of args */ + + SUBL $16, SP /* Make some room for our SP-refetch logic */ + MOVL SP, BX /* Copy address to new, executable stack space to BX */ + +/* This part fills our executable stack space with instructions. We + need to get the program counter, first, with a little hack. */ + MOVL $0x000003e8, 0(SP) /* Copy 'call (cur ip+8)' */ + MOVL $0x00000000, 4(SP) /* '00' for call address, rest is garbage */ + MOVL $0x5a909090, 8(SP) /* 'nop, nop, nop, pop edx' to get eip+5 in edx */ + MOVL $0xc30b628b,12(SP) /* Restore stack ptr and return: 'mov [edx+11] to esp, ret' */ + + SUBL CX, SP /* allocate 'size' bytes on stack for args */ + MOVL SP, DI /* DI = stack args */ + + SHRL $2, SP /* Align stack. */ + SHLL $2, SP /* " " */ + + /* I didn't figure out how to use MOVSB with the 8a syntax. The following + can probably be written in a better way. */ + JMP copy_loop_cmp +copy_loop: + MOVL 0(SI), AX /* Copy args. */ + MOVL AX, 0(DI) + SUBL $4, CX + ADDL $4, SI + ADDL $4, DI +copy_loop_cmp: + CMPL CX, $0 + JGT copy_loop + + /* Check if we need to push a pointer to long long that might be used as + container for 64-bit return values. */ + CMPL DX, $0 + JEQ call_ffi + PUSHL DX + + /* Now we try to fake a call, meaning setting up our fake return address, + and then jumping to the FFI call. This should call the function, but + the return will jump into our stack space we reserved above. */ +call_ffi: + PUSHL BX + MOVL 4(BP), BX + JMP BX + + /* Note that there is no return here, b/c the return is in the asm code + above, that has been generated on the fly. */ + + +/* Main call for 32 bit integer return values and floating point arguments. + See call_main for explanation. */ +TEXT dcCall_x86_plan9(SB), $0 + + MOVL $0, DX + JMP call_main + + +/* Call for 64 bit integer return values. + See call_main for explanation. */ +TEXT dcCall_x86_plan9_ll(SB), $0 + + MOVL 16(SP), DX /* Copy pointer to variable for return value. */ + JMP call_main