annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
1 /*
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
2
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
3 Package: dyncall
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
4 Library: dyncall
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
5 File: dyncall/dyncall_call_x86_8a.s
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
6 Description: All x86 abi call kernel implementations in Plan9's assembler
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
7 License:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
8
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
9 Copyright (c) 2007-2011 Daniel Adler <dadler@uni-goettingen.de>,
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
10 Tassilo Philipp <tphilipp@potion-studios.com>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
11
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
12 Permission to use, copy, modify, and distribute this software for any
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
13 purpose with or without fee is hereby granted, provided that the above
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
14 copyright notice and this permission notice appear in all copies.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
15
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
23
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
24 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
25
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
26
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
27
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
28 /* 64 bit integer return value calls require caller to create space for return
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
29 value, and pass a pointer to it as 1st argument. This main function handles
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
30 all cases (32 and 64 bit integers, as well as floats and doubles), however,
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
31 it has to be called through the 2 corresponding functions at the end of
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
32 this file.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
33 In order to keep things simple, we basically put the pointer to the
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
34 return value in EDX and call the other assembler code, above. If EDX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
35 is not null, then the code below will push it to the stack as first
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
36 argument.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
37 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
38
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
39 call_main:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
40
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
41 /* Since all registers except SP are scratch, and we have a variable
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
42 argument size depending on the function to call, we have to find
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
43 a way to store and restore SP.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
44 The idea is to replace the return address with a custom one on the
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
45 stack, and to put some logic there, jumping back to the real
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
46 return address. This allows us, to put the SP somewhere next to
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
47 the fake return address on the stack, so that we can get it back
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
48 with a fixed offset (relative to the program counter, in our case).
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
49
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
50 The only real issue with this approach would be a non-executable
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
51 stack. However, Plan9 doesn't support w^x at the time of writing.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
52 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
53
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
54 /* On the stack at this point:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
55 RETADDR 0(SP)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
56 FUNPTR 4(SP)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
57 ARGS 8(SP)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
58 SIZE 12(SP)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
59 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
60
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
61 MOVL SP, BP /* base pointer for convenience */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
62 PUSHL SP /* save stack pointer */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
63
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
64 MOVL 8(BP), SI /* SI = pointer on args */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
65 MOVL 12(BP), CX /* CX = size of args */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
66
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
67 SUBL $16, SP /* Make some room for our SP-refetch logic */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
68 MOVL SP, BX /* Copy address to new, executable stack space to BX */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
69
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
70 /* This part fills our executable stack space with instructions. We
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
71 need to get the program counter, first, with a little hack. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
72 MOVL $0x000003e8, 0(SP) /* Copy 'call (cur ip+8)' */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
73 MOVL $0x00000000, 4(SP) /* '00' for call address, rest is garbage */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
74 MOVL $0x5a909090, 8(SP) /* 'nop, nop, nop, pop edx' to get eip+5 in edx */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
75 MOVL $0xc30b628b,12(SP) /* Restore stack ptr and return: 'mov [edx+11] to esp, ret' */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
76
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
77 SUBL CX, SP /* allocate 'size' bytes on stack for args */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
78 MOVL SP, DI /* DI = stack args */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
79
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
80 SHRL $2, SP /* Align stack. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
81 SHLL $2, SP /* " " */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
82
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
83 /* I didn't figure out how to use MOVSB with the 8a syntax. The following
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
84 can probably be written in a better way. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
85 JMP copy_loop_cmp
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
86 copy_loop:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
87 MOVL 0(SI), AX /* Copy args. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
88 MOVL AX, 0(DI)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
89 SUBL $4, CX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
90 ADDL $4, SI
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
91 ADDL $4, DI
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
92 copy_loop_cmp:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
93 CMPL CX, $0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
94 JGT copy_loop
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
95
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
96 /* Check if we need to push a pointer to long long that might be used as
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
97 container for 64-bit return values. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
98 CMPL DX, $0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
99 JEQ call_ffi
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
100 PUSHL DX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
101
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
102 /* Now we try to fake a call, meaning setting up our fake return address,
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
103 and then jumping to the FFI call. This should call the function, but
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
104 the return will jump into our stack space we reserved above. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
105 call_ffi:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
106 PUSHL BX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
107 MOVL 4(BP), BX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
108 JMP BX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
109
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
110 /* Note that there is no return here, b/c the return is in the asm code
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
111 above, that has been generated on the fly. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
112
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
113
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
114 /* Main call for 32 bit integer return values and floating point arguments.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
115 See call_main for explanation. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
116 TEXT dcCall_x86_plan9(SB), $0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
117
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
118 MOVL $0, DX
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
119 JMP call_main
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
120
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
121
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
122 /* Call for 64 bit integer return values.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
123 See call_main for explanation. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
124 TEXT dcCall_x86_plan9_ll(SB), $0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
125
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
126 MOVL 16(SP), DX /* Copy pointer to variable for return value. */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
127 JMP call_main