1 /* Copyright (C) 2011-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <http://www.gnu.org/licenses/>. */
22 /* This function is called via the PLT header, which is called
23 from an individual PLT entry.
25 At this point we have several values passed in:
27 lr: return address to original user code
28 r28: the tpnt value to pass to _dl_runtime_resolver
29 r29: the PLT index of the invoked jump table entry.
31 We set up a frame entry that looks like this (in int_reg_t units):
33 +57: r25 return values from function...
42 +27: r25 arguments to function...
47 +1: standard ABI slot (sp)
48 +0: standard ABI slot (callee lr)
50 The entries from "stackframe" up are only used in _dl_profile_resolve.
51 We save and restore r0 through r25, rather than the strictly
52 architected r0 through r9, to support unusual calling conventions;
53 for example, __tls_get_addr takes r0 and returns r0, but promises
54 not to clobber r1 through r24 to support its usual fast path. */
56 #define FRAME_SP (1 * REGSIZE)
57 #define FRAME_REGS (2 * REGSIZE)
58 #define FRAME_LR (28 * REGSIZE) /* Must follow FRAME_REGS */
59 #define FRAME_STACKFRAME (29 * REGSIZE)
60 #define FRAME_TPNT (30 * REGSIZE)
61 #define FRAME_INDEX (31 * REGSIZE)
62 #define FRAME_RETVAL (32 * REGSIZE)
64 #define FRAME_SIZE_SMALL (30 * REGSIZE)
65 #define FRAME_SIZE_LARGE (58 * REGSIZE)
67 #define FOR_EACH_REG(f) \
68 f(r0); f(r1); f(r2); f(r3); \
69 f(r4); f(r5); f(r6); f(r7); \
70 f(r8); f(r9); f(r10); f(r11); \
71 f(r12); f(r13); f(r14); f(r15); \
72 f(r16); f(r17); f(r18); f(r19); \
73 f(r20); f(r21); f(r22); f(r23); \
76 #define SAVE(REG) { ST r27, REG; ADDI_PTR r27, r27, REGSIZE }
77 #define RESTORE(REG) { LD REG, r27; ADDI_PTR r27, r27, REGSIZE }
79 .macro dl_resolve, name, profile, framesize
83 /* Note that cpp expands ENTRY(\name) incorrectly. */
93 ADDLI_PTR sp, sp, -\framesize
94 ADDLI_PTR r27, sp, FRAME_SP - \framesize
96 cfi_def_cfa_offset (\framesize)
99 ADDI_PTR r27, r27, FRAME_REGS - FRAME_SP
104 ADDLI_PTR r27, sp, FRAME_TPNT
106 cfi_offset (lr, FRAME_LR - \framesize)
109 move r0, r28 /* tpnt value */
111 ADDI_PTR r27, r27, FRAME_INDEX - FRAME_TPNT
114 move r1, r29 /* PLT index */
118 move r2, lr /* retaddr */
119 ADDI_PTR r3, sp, FRAME_REGS /* La_tile_regs pointer */
122 ADDLI_PTR r4, sp, FRAME_STACKFRAME /* framesize pointer */
123 jal _dl_profile_fixup
125 ADDLI_PTR r28, sp, FRAME_STACKFRAME
130 move r0, r28 /* tpnt value 1 */
131 move r1, r29 /* PLT index 2 */
136 /* Copy aside the return value so we can restore r0 below. */
138 /* Set up r27 to let us start restoring registers. */
139 ADDLI_PTR r27, sp, FRAME_REGS
141 FOR_EACH_REG(RESTORE)
143 ADDLI_PTR r28, sp, FRAME_STACKFRAME
148 /* Restore original user return address. */
150 /* Pop off our stack frame. */
151 ADDLI_PTR sp, sp, \framesize
153 cfi_def_cfa_offset (0)
154 jr r29 /* Transfer control to freshly loaded code. */
155 jrp lr /* Keep backtracer happy. */
158 1: jalr r29 /* Call resolved function. */
160 ADDLI_PTR r28, sp, FRAME_TPNT
161 ADDLI_PTR r27, sp, FRAME_RETVAL
166 ADDI_PTR r28, r28, FRAME_INDEX - FRAME_TPNT
170 ADDLI_PTR r2, sp, FRAME_REGS
173 ADDLI_PTR r3, sp, FRAME_RETVAL
177 ADDLI_PTR lr, sp, FRAME_LR
178 ADDLI_PTR r27, sp, FRAME_RETVAL
180 FOR_EACH_REG(RESTORE)
183 ADDLI_PTR sp, sp, \framesize
190 dl_resolve _dl_runtime_resolve, 0, FRAME_SIZE_SMALL
192 dl_resolve _dl_runtime_profile, 1, FRAME_SIZE_LARGE