Add arm-nacl port.
[glibc.git] / sysdeps / arm / nacl / dl-trampoline.S
blob47bc0cac795ebe3b15a4ae64e46da01db96a2ce4
1 /* PLT trampolines.  ARM/NaCl version.
2    Copyright (C) 2015 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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/>.  */
19 #include <sysdep.h>
21         .syntax unified
22         .text
24 @ Change &GOT[n+3] into 8*n.  Note relocs are 8 bytes each.
25 .macro compute_reloc_arg pltgot, got2
26         sub r1, \pltgot, \got2  @ r1 = &GOT[n+3] - &GOT[2] = 4*(n-1)
27         sub r1, r1, #4          @ r1 = 4*n
28         add r1, r1, r1          @ r1 *= 2 = 8*n
29 .endm
31         CFI_SECTIONS
32         .globl _dl_runtime_resolve
33         .type _dl_runtime_resolve, %function
34         .p2align 4
35 _dl_runtime_resolve:
36         cfi_startproc
37         cfi_adjust_cfa_offset (8)
39         @ We get called with:
40         @       lr contains the return address from this call
41         @       stack[1] contains &GOT[n+3] (pointer to function)
42         @       stack[0] points to &GOT[2]
44         ldr ip, [sp]            @ ip gets &GOT[2]
46         @ Save the argument registers and the return address.
47         @ r4 doesn't need to be saved, but it makes the total
48         @ adjustment to sp (including the two words pushed by
49         @ the PLT code) an even eight words, so sp stays aligned.
50         push {r0-r4, lr}
51         cfi_adjust_cfa_offset (24)
52         cfi_rel_offset (r0, 0)
53         cfi_rel_offset (r1, 4)
54         cfi_rel_offset (r2, 8)
55         cfi_rel_offset (r3, 12)
56         cfi_rel_offset (r4, 16)
57         cfi_rel_offset (lr, 20)
59         ldr r1, [sp, #28]       @ r1 gets &GOT[n+3]
61         @ Get the 'struct link_map *' for the first argument to _dl_fixup.
62         sfi_breg ip, ldr r0, [\B, #-4]
64         @ Get the reloc offset for the second argument to _dl_fixup.
65         compute_reloc_arg r1, ip
67         @ This does the real work, and returns the real call target.
68         sfi_bl _dl_fixup
69         mov ip, r0
71         @ Restore the saved registers.
72         pop {r0-r4, lr}
73         cfi_adjust_cfa_offset (-24)
74         cfi_restore (r0)
75         cfi_restore (r1)
76         cfi_restore (r2)
77         cfi_restore (r3)
78         cfi_restore (r4)
79         cfi_restore (lr)
81         @ Now compensate for the two words pushed by the PLT code.
82         sfi_sp add sp, #8
83         cfi_adjust_cfa_offset (-8)
85         @ Finally, jump to the newfound call target.
86         sfi_bx ip
88         cfi_endproc
89         .size _dl_runtime_resolve, .-_dl_runtime_resolve
91 #ifndef PROF
92         .globl _dl_runtime_profile
93         .type _dl_runtime_profile, #function
94         .p2align 4
95 _dl_runtime_profile:
96         cfi_startproc
97         cfi_adjust_cfa_offset (8)
99         @ We get called with:
100         @       lr contains the return address from this call
101         @       stack[1] contains &GOT[n+3] (pointer to function)
102         @       stack[0] points to &GOT[2]
104         @ Stack layout:
105         @ sp + 204              framesize returned from pltenter
106         @ sp + 12               La_arm_regs
107         @ sp + 4                Saved two arguments to _dl_profile_fixup
108         @ sp + 0                outgoing argument to _dl_profile_fixup
109         @ For now, we only save the general purpose registers.
110 # define PLTEXIT_ARGS           4
111 # define LA_ARM_REGS            (PLTEXIT_ARGS + 8)
112 # define LA_ARM_REGS_SIZE       (4 * (4 + 1 + 1 + 42))
113 # define PLTENTER_FRAMESIZE     (LA_ARM_REGS + LA_ARM_REGS_SIZE)
114 # define FRAMESIZE              (((PLTENTER_FRAMESIZE + 4) + 15) & -16)
116         @ The NaCl ABI requires that sp be aligned to 16 bytes at call
117         @ sites.  Assuming that was met on entry to the PLT, sp is
118         @ now exactly 8 bytes misaligned.
119         sfi_sp sub sp, #(FRAMESIZE - 8)
120         cfi_def_cfa_offset (FRAMESIZE)
122         @ Store the argument registers in La_arm_regs.
123         strd r0, r1, [sp, #LA_ARM_REGS]
124         cfi_offset (r0, LA_ARM_REGS + 0)
125         cfi_offset (r1, LA_ARM_REGS + 4)
126         strd r2, r3, [sp, #(LA_ARM_REGS + 8)]
127         cfi_offset (r2, LA_ARM_REGS + 8)
128         cfi_offset (r3, LA_ARM_REGS + 12)
130         ldr ip, [sp, #(FRAMESIZE - 8)]          @ ip gets &GOT[2]
131         ldr r3, [sp, #(FRAMESIZE - 4)]          @ r3 gets &GOT[n+3]
133         @ Recover the incoming sp and lr and save those in La_arm_regs.
134         add r0, sp, #FRAMESIZE
135         mov r1, lr
136         strd r0, r1, [sp, #(LA_ARM_REGS + 16)]
137         cfi_offset (sp, LA_ARM_REGS + 16)
138         cfi_offset (lr, LA_ARM_REGS + 20)
140         @ Get the 'struct link_map *' for the first arg to _dl_profile_fixup.
141         sfi_breg ip, ldr r0, [\B, #-4]
143         @ Get the reloc offset for the second argument to _dl_profile_fixup.
144         compute_reloc_arg r3, ip
146         @ The third argument is the original return address, still in lr.
147         mov r2, lr
149         @ Compute the fourth argument, the La_arm_regs pointer.
150         add r3, sp, #PLTEXIT_ARGS
152         @ Compute the fifth argument, the address of the 'framesize'
153         @ out parameter, and store it at the top of the stack.
154         add ip, sp, #PLTENTER_FRAMESIZE
155         str ip, [sp]
157         @ Save away the first two arguments, which we will need
158         @ again for _dl_call_pltexit, below.
159         strd r0, r1, [sp, #PLTEXIT_ARGS]
161         @ This does the real work, and returns the real call target.
162         sfi_bl _dl_profile_fixup
164         @ The address to call is now in r0.
166         @ Check whether we're wrapping this function,
167         @ i.e. if the framesize out parameter is >= 0.
168         ldr     ip, [sp, #PLTENTER_FRAMESIZE]
169         cmp     ip, #0
170         bge     1f
171         cfi_remember_state
173         @ Save _dl_profile_fixup's return value: the real call target.
174         mov ip, r0
176         @ Restore the registers from the La_arm_regs (perhaps as modified
177         @ by audit modules' pltenter functions).
178         add r1, sp, #LA_ARM_REGS
179         sfi_sp sfi_breg r1, ldmia \B, {r0-r3, sp, lr}
180         cfi_def_cfa_offset (0)
181         cfi_restore (r0)
182         cfi_restore (r1)
183         cfi_restore (r2)
184         cfi_restore (r3)
185         cfi_restore (sp)
186         cfi_restore (lr)
188         @ Finally, jump to the newfound call target.
189         sfi_bx ip
191 1:      cfi_restore_state
192         @ The new frame size is in ip.
194         @ Save the fp in the stack slot previously used for the fifth
195         @ argument to _dl_profile_fixup.
196         str fp, [sp]
197         cfi_offset (fp, 0)
199         @ Save the result of _dl_profile_fixup, the real call target.
200         @ We'll reuse the stack slot just used for the 'framesize'
201         @ out parameter to _dl_profile_fixup.
202         str r0, [sp, #PLTENTER_FRAMESIZE]
204         @ Stack layout:
205         @ fp + 264              call target
206         @ fp + 72               La_arm_regs
207         @ fp + 68               Saved two arguments to _dl_profile_fixup
208         @ fp + 64               saved fp
209         @ fp + 0                La_arm_retval
210         @ sp..fp                copied incoming stack space (plus alignment)
211         @ For now, we only save the general purpose registers.
212 # define FP_LA_ARM_RETVAL       0
213 # define LA_ARM_RETVAL_SIZE     (4 * (4 + 12))
214 # define FP_SAVED_FP            LA_ARM_RETVAL_SIZE
215 # define FP_PLTEXIT_ARGS        (FP_SAVED_FP + 4)
216 # define FP_LA_ARM_REGS         (FP_PLTEXIT_ARGS + 8)
217 # define FP_CALL_TARGET         (FP_LA_ARM_REGS + LA_ARM_REGS_SIZE)
218 # define FP_FRAMESIZE           (FP_CALL_TARGET + 4)
220         sub fp, sp, #(FP_FRAMESIZE - FRAMESIZE)
221         cfi_def_cfa (fp, FP_FRAMESIZE)
223         sub r1, fp, ip
224         @ This doesn't need sfi_sp because we just include the
225         @ sandboxing mask along with the alignment mask.
226         bic sp, r1, #0xc000000f
228         @ Copy the stack arguments.  The audit modules' pltenter
229         @ function(s) decided how much needs to be copied.
230         @ Load the sp as modified by pltenter functions, rather
231         @ than what we think the incoming sp was (fp + FP_FRAMESIZE).
232         sfi_breg fp, ldr r1, [\B, #(FP_LA_ARM_REGS + 16)]
233         mov r0, sp
234         mov r2, ip
235         sfi_bl memcpy
237         @ Load up the arguments from La_arm_regs and call the user's function.
238         sfi_breg fp, ldr ip, [\B, #FP_CALL_TARGET]
239         sfi_breg fp, ldrd r0, r1, [\B, #FP_LA_ARM_REGS]
240         sfi_breg fp, ldrd r2, r3, [\B, #(FP_LA_ARM_REGS + 8)]
241         sfi_blx ip
243         @ Stash the return value registers in La_arm_retval.
244         sfi_breg fp, strd r0, r1, [\B, #FP_LA_ARM_RETVAL]
245         sfi_breg fp, strd r2, r3, [\B, #(FP_LA_ARM_RETVAL + 8)]
247         @ Call pltexit.  We saved the first two arguments earlier--they
248         @ are the same ones passed to _dl_profile_fixup.  The latter two
249         @ arguments are La_arm_regs and La_arm_retval blocks, respectively.
250         sfi_breg fp, ldrd r0, r1, [\B, #FP_PLTEXIT_ARGS]
251         add r2, fp, #FP_LA_ARM_REGS
252         add r3, fp, #FP_LA_ARM_RETVAL
253         sfi_bl _dl_call_pltexit
255         @ Reload the saved return value registers for the caller.
256         sfi_breg fp, ldrd r0, r1, [\B, #FP_LA_ARM_RETVAL]
257         sfi_breg fp, ldrd r2, r3, [\B, #(FP_LA_ARM_RETVAL + 8)]
259         @ Unwind the frame.
260         sfi_sp mov sp, fp
261         cfi_def_cfa_register (sp)
262         ldr fp, [sp, #FP_SAVED_FP]
263         cfi_restore (fp)
264         @ Reload the lr and sp values from La_arm_regs, where they
265         @ might have been modified by pltenter functions, rather than
266         @ computing what we think the incoming value was.
267         ldr lr, [sp, #(FP_LA_ARM_REGS + 20)]
268         cfi_restore (lr)
269         sfi_sp ldr sp, [sp, #(FP_LA_ARM_REGS + 16)]
270         cfi_def_cfa_offset (0)
272         @ Finally, return to the caller.
273         sfi_bx lr
275         cfi_endproc
276         .size _dl_runtime_profile, .-_dl_runtime_profile
277 #endif
278         .previous