summaryrefslogtreecommitdiff
path: root/ports/sysdeps/arm/dl-trampoline.S
diff options
context:
space:
mode:
Diffstat (limited to 'ports/sysdeps/arm/dl-trampoline.S')
-rw-r--r--ports/sysdeps/arm/dl-trampoline.S217
1 files changed, 217 insertions, 0 deletions
diff --git a/ports/sysdeps/arm/dl-trampoline.S b/ports/sysdeps/arm/dl-trampoline.S
new file mode 100644
index 0000000000..370bda3467
--- /dev/null
+++ b/ports/sysdeps/arm/dl-trampoline.S
@@ -0,0 +1,217 @@
+/* PLT trampolines. ARM version.
+ Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <libc-symbols.h>
+
+#if defined(__USE_BX__)
+#define BX(x) bx x
+#else
+#define BX(x) mov pc, x
+#endif
+
+ .text
+ .globl _dl_runtime_resolve
+ .type _dl_runtime_resolve, #function
+ .cfi_sections .debug_frame
+ cfi_startproc
+ .align 2
+_dl_runtime_resolve:
+ cfi_adjust_cfa_offset (4)
+ cfi_rel_offset (lr, 0)
+
+ @ we get called with
+ @ stack[0] contains the return address from this call
+ @ ip contains &GOT[n+3] (pointer to function)
+ @ lr points to &GOT[2]
+
+ @ Save arguments. We save r4 to realign the stack.
+ stmdb sp!,{r0-r4}
+ cfi_adjust_cfa_offset (20)
+ cfi_rel_offset (r0, 0)
+ cfi_rel_offset (r1, 4)
+ cfi_rel_offset (r2, 8)
+ cfi_rel_offset (r3, 12)
+
+ @ get pointer to linker struct
+ ldr r0, [lr, #-4]
+
+ @ prepare to call _dl_fixup()
+ @ change &GOT[n+3] into 8*n NOTE: reloc are 8 bytes each
+ sub r1, ip, lr
+ sub r1, r1, #4
+ add r1, r1, r1
+
+ @ call fixup routine
+ bl _dl_fixup
+
+ @ save the return
+ mov ip, r0
+
+ @ get arguments and return address back. We restore r4
+ @ only to realign the stack.
+ ldmia sp!, {r0-r4,lr}
+ cfi_adjust_cfa_offset (-24)
+
+ @ jump to the newly found address
+ BX(ip)
+
+ cfi_endproc
+ .size _dl_runtime_resolve, .-_dl_runtime_resolve
+
+#ifndef PROF
+ .globl _dl_runtime_profile
+ .type _dl_runtime_profile, #function
+ .cfi_sections .debug_frame
+ cfi_startproc
+ .align 2
+_dl_runtime_profile:
+ cfi_adjust_cfa_offset (4)
+ cfi_rel_offset (lr, 0)
+
+ @ we get called with
+ @ stack[0] contains the return address from this call
+ @ ip contains &GOT[n+3] (pointer to function)
+ @ lr points to &GOT[2]
+
+ @ Stack layout:
+ @ 212 - saved lr
+ @ 208 - framesize returned from pltenter
+ @ 16 - La_arm_regs
+ @ 8 - Saved two arguments to _dl_profile_fixup
+ @ 4 - Saved result of _dl_profile_fixup
+ @ 0 - outgoing argument to _dl_profile_fixup
+ @ For now, we only save the general purpose registers.
+
+ sub sp, sp, #196
+ cfi_adjust_cfa_offset (196)
+ stmia sp, {r0-r3}
+ cfi_rel_offset (r0, 0)
+ cfi_rel_offset (r1, 4)
+ cfi_rel_offset (r2, 8)
+ cfi_rel_offset (r3, 12)
+
+ sub sp, sp, #16
+ cfi_adjust_cfa_offset (16)
+
+ @ Save sp and lr.
+ add r0, sp, #216
+ str r0, [sp, #32]
+ ldr r2, [sp, #212]
+ str r2, [sp, #36]
+
+ @ get pointer to linker struct
+ ldr r0, [lr, #-4]
+
+ @ prepare to call _dl_profile_fixup()
+ @ change &GOT[n+3] into 8*n NOTE: reloc are 8 bytes each
+ sub r1, ip, lr
+ sub r1, r1, #4
+ add r1, r1, r1
+
+ @ Save these two arguments for pltexit.
+ add r3, sp, #8
+ stmia r3!, {r0,r1}
+
+ @ Set up extra args for _dl_profile_fixup.
+ @ r2 and r3 are already loaded.
+ add ip, sp, #208
+ str ip, [sp, #0]
+
+ @ call profiling fixup routine
+ bl _dl_profile_fixup
+
+ @ The address to call is now in r0.
+
+ @ Check whether we're wrapping this function.
+ ldr ip, [sp, #208]
+ cmp ip, #0
+ bge 1f
+ cfi_remember_state
+
+ @ save the return
+ mov ip, r0
+
+ @ get arguments and return address back
+ add sp, sp, #16
+ cfi_adjust_cfa_offset (-16)
+ ldmia sp, {r0-r3,sp,lr}
+ cfi_adjust_cfa_offset (-200)
+
+ @ jump to the newly found address
+ BX(ip)
+
+ cfi_restore_state
+1:
+ @ The new frame size is in ip.
+
+ @ New stack layout:
+ @ 268 - saved r7
+ @ 264 - saved result of _dl_profile_fixup
+ @ 72 - La_arm_regs
+ @ 64 - Saved two arguments to _dl_profile_fixup
+ @ 0 - La_arm_retval
+ @ For now, we only save the general purpose registers.
+
+ @ Build the new frame.
+ str r7, [sp, #212]
+ cfi_rel_offset (r7, 212)
+ sub r7, sp, #56
+ cfi_def_cfa_register (r7)
+ cfi_adjust_cfa_offset (56)
+ sub sp, sp, ip
+ bic sp, sp, #7
+
+ @ Save the _dl_profile_fixup result around the call to memcpy.
+ str r0, [r7, #264]
+
+ @ Copy the stack arguments.
+ mov r0, sp
+ add r1, r7, #272
+ mov r2, ip
+ bl memcpy
+
+ @ Call the function.
+ add ip, r7, #72
+ ldmia ip, {r0-r3}
+ ldr ip, [r7, #264]
+ mov lr, pc
+ BX(ip)
+ stmia r7, {r0-r3}
+
+ @ Call pltexit.
+ add ip, r7, #64
+ ldmia ip, {r0,r1}
+ add r2, r7, #72
+ add r3, r7, #0
+ bl _dl_call_pltexit
+
+ @ Return to caller.
+ ldmia r7, {r0-r3}
+ mov sp, r7
+ cfi_def_cfa_register (sp)
+ ldr r7, [sp, #268]
+ ldr lr, [sp, #92]
+ add sp, sp, #272
+ cfi_adjust_cfa_offset (-272)
+ BX(lr)
+
+ cfi_endproc
+ .size _dl_runtime_profile, .-_dl_runtime_profile
+#endif
+ .previous