summaryrefslogtreecommitdiff
path: root/rts/AdjustorAsm.S
blob: ba08548f849d735e6358cd72e436884edbc629d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "../includes/ghcconfig.h"

/* ******************************** PowerPC ******************************** */

#if defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH)
#if !(defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS))
    /* The following code applies, with some differences,
       to all powerpc platforms except for powerpc32-linux,
       whose calling convention is annoyingly complex.
    */


    /* The code is "almost" the same for
       32-bit and for 64-bit
    */
#if defined(powerpc64_HOST_ARCH)
#define WS          8
#define LOAD        ld
#define STORE       std
#else
#define WS          4
#define LOAD        lwz
#define STORE       stw
#endif

    /* Some info about stack frame layout */
#define LINK_SLOT           (2*WS)
#define LINKAGE_AREA_SIZE   (6*WS)

    /* The following defines mirror struct AdjustorStub
       from Adjustor.c. Make sure to keep these in sync.
    */
#if defined(powerpc_HOST_ARCH) && defined(darwin_HOST_OS)
#define HEADER_WORDS   6
#elif defined(powerpc64_HOST_ARCH) && defined(darwin_HOST_OS)
#else
#define HEADER_WORDS   3
#endif

#define HPTR_OFF        ((HEADER_WORDS    )*WS)
#define WPTR_OFF        ((HEADER_WORDS + 1)*WS)
#define FRAMESIZE_OFF   ((HEADER_WORDS + 2)*WS)
#define EXTRA_WORDS_OFF ((HEADER_WORDS + 3)*WS)

    /* Darwin insists on register names, everyone else prefers
       to use numbers. */
#if !defined(darwin_HOST_OS)
#define r0 0
#define r1 1
#define r2 2
#define r3 3
#define r4 4
#define r5 5
#define r6 6
#define r7 7
#define r8 8
#define r9 9
#define r10 10
#define r11 11
#define r12 12

#define r30 30
#define r31 31
#endif

#if defined(aix_HOST_OS)
/* IBM's assembler needs a different pseudo-op to declare a .text section */
.csect .text[PR]
#else
.text
#endif
#if LEADING_UNDERSCORE
    .globl _adjustorCode
_adjustorCode:
#else
    .globl adjustorCode
        /* Note that we don't build a function descriptor
           for AIX-derived ABIs here. This will happen at runtime
           in createAdjustor().
        */
adjustorCode:
#endif
    /* On entry, r2 will point to the AdjustorStub data structure. */

        /* save the link */
    mflr    r0
    STORE   r0, LINK_SLOT(r1)
    
        /* set up stack frame */
    LOAD    r12, FRAMESIZE_OFF(r2)
#if defined(powerpc64_HOST_ARCH)
    stdux   r1, r1, r12
#else   
    stwux   r1, r1, r12
#endif

        /* Save some regs so that we can use them.
           Note that we use the "Red Zone" below the stack pointer.
        */
    STORE   r31, -WS(r1)
    STORE   r30, -2*WS(r1)

    mr      r31, r1
    subf    r30, r12, r31

    LOAD    r12, EXTRA_WORDS_OFF(r2)
    mtctr   r12
    b       L2
L1:
    LOAD    r0, LINKAGE_AREA_SIZE +  8*WS(r30)
    STORE   r0, LINKAGE_AREA_SIZE + 10*WS(r31)
    addi    r30, r30, WS
    addi    r31, r31, WS
L2:
    bdnz    L1

        /* Restore r30 and r31 now.
        */
    LOAD    r31, -WS(r1)
    LOAD    r30, -2*WS(r1)

    STORE   r10, LINKAGE_AREA_SIZE + 9*WS(r1)
    STORE   r9,  LINKAGE_AREA_SIZE + 8*WS(r1)
    mr      r10, r8
    mr      r9, r7
    mr      r8, r6
    mr      r7, r5
    mr      r6, r4
    mr      r5, r3

    LOAD    r3, HPTR_OFF(r2)

    LOAD    r12, WPTR_OFF(r2)
#if defined(darwin_HOST_OS)
    mtctr   r12
#else
    LOAD    r0, 0(r12)
        /* The function we're calling will never be a nested function,
           so we don't load r11. 
        */
    mtctr   r0
    LOAD    r2, WS(r12)
#endif
    bctrl

    LOAD    r1, 0(r1)
    LOAD    r0, LINK_SLOT(r1)
    mtlr    r0
    blr
#endif

/* ********************************* i386 ********************************** */

#elif defined(i386_HOST_ARCH)

#define WS              4
#define RETVAL_OFF      5
#define HEADER_BYTES    8

#define HPTR_OFF        HEADER_BYTES
#define WPTR_OFF        (HEADER_BYTES + 1*WS)
#define FRAMESIZE_OFF   (HEADER_BYTES + 2*WS)
#define ARGWORDS_OFF    (HEADER_BYTES + 3*WS)

#if defined(LEADING_UNDERSCORE)
    .globl _adjustorCode
_adjustorCode:
#else
    .globl adjustorCode
adjustorCode:
#endif
    popl    %eax
    subl    $RETVAL_OFF, %eax
    
    pushl   %ebp
    movl    %esp, %ebp
    
    subl    FRAMESIZE_OFF(%eax), %esp

    pushl   %esi
    pushl   %edi
        
    leal    8(%ebp), %esi
    leal    12(%esp), %edi
    movl    ARGWORDS_OFF(%eax), %ecx
    rep
    movsl
    
    popl    %edi
    popl    %esi
    
    pushl   HPTR_OFF(%eax)
    call    *WPTR_OFF(%eax)
    
    leave
    ret
#endif

/* mark stack as nonexecutable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",@progbits
#endif