summaryrefslogtreecommitdiff
path: root/ports/sysdeps/tile/dl-trampoline.S
diff options
context:
space:
mode:
Diffstat (limited to 'ports/sysdeps/tile/dl-trampoline.S')
-rw-r--r--ports/sysdeps/tile/dl-trampoline.S193
1 files changed, 193 insertions, 0 deletions
diff --git a/ports/sysdeps/tile/dl-trampoline.S b/ports/sysdeps/tile/dl-trampoline.S
new file mode 100644
index 0000000000..3478824957
--- /dev/null
+++ b/ports/sysdeps/tile/dl-trampoline.S
@@ -0,0 +1,193 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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 <arch/abi.h>
+
+/* This function is called via the PLT header, which is called
+ from an individual PLT entry.
+
+ At this point we have several values passed in:
+
+ lr: return address to original user code
+ r28: the tpnt value to pass to _dl_runtime_resolver
+ r29: the PLT index of the invoked jump table entry.
+
+ We set up a frame entry that looks like this (in int_reg_t units):
+
+ +57: r25 return values from function...
+ +56: r24
+ [...]
+ +33: r1
+ +32: r0
+ +31: PLT index
+ +30: tpnt
+ +29: stackframe
+ +28: caller lr
+ +27: r25 arguments to function...
+ +26: r24
+ [...]
+ +3: r1
+ +2: r0
+ +1: standard ABI slot (sp)
+ +0: standard ABI slot (callee lr)
+
+ The entries from "stackframe" up are only used in _dl_profile_resolve.
+ We save and restore r0 through r25, rather than the strictly
+ architected r0 through r9, to support unusual calling conventions;
+ for example, __tls_get_addr takes r0 and returns r0, but promises
+ not to clobber r1 through r24 to support its usual fast path. */
+
+#define FRAME_SP (1 * REGSIZE)
+#define FRAME_REGS (2 * REGSIZE)
+#define FRAME_LR (28 * REGSIZE) /* Must follow FRAME_REGS */
+#define FRAME_STACKFRAME (29 * REGSIZE)
+#define FRAME_TPNT (30 * REGSIZE)
+#define FRAME_INDEX (31 * REGSIZE)
+#define FRAME_RETVAL (32 * REGSIZE)
+
+#define FRAME_SIZE_SMALL (30 * REGSIZE)
+#define FRAME_SIZE_LARGE (58 * REGSIZE)
+
+#define FOR_EACH_REG(f) \
+ f(r0); f(r1); f(r2); f(r3); \
+ f(r4); f(r5); f(r6); f(r7); \
+ f(r8); f(r9); f(r10); f(r11); \
+ f(r12); f(r13); f(r14); f(r15); \
+ f(r16); f(r17); f(r18); f(r19); \
+ f(r20); f(r21); f(r22); f(r23); \
+ f(r24); f(r25)
+
+#define SAVE(REG) { ST r27, REG; ADDI_PTR r27, r27, REGSIZE }
+#define RESTORE(REG) { LD REG, r27; ADDI_PTR r27, r27, REGSIZE }
+
+ .macro dl_resolve, name, profile, framesize
+.text
+.global \name
+.hidden \name
+/* Note that cpp expands ENTRY(\name) incorrectly. */
+.type \name,@function
+.align 8
+\name:
+ cfi_startproc
+ {
+ ST sp, lr
+ move r26, sp
+ }
+ {
+ ADDLI_PTR sp, sp, -\framesize
+ ADDLI_PTR r27, sp, FRAME_SP - \framesize
+ }
+ cfi_def_cfa_offset (\framesize)
+ {
+ ST r27, r26
+ ADDI_PTR r27, r27, FRAME_REGS - FRAME_SP
+ }
+ FOR_EACH_REG(SAVE)
+ {
+ ST r27, lr
+ ADDLI_PTR r27, sp, FRAME_TPNT
+ }
+ cfi_offset (lr, FRAME_LR - \framesize)
+ .if \profile
+ {
+ move r0, r28 /* tpnt value */
+ ST r27, r28
+ ADDI_PTR r27, r27, FRAME_INDEX - FRAME_TPNT
+ }
+ {
+ move r1, r29 /* PLT index */
+ ST r27, r29
+ }
+ {
+ move r2, lr /* retaddr */
+ ADDI_PTR r3, sp, FRAME_REGS /* La_tile_regs pointer */
+ }
+ {
+ ADDLI_PTR r4, sp, FRAME_STACKFRAME /* framesize pointer */
+ jal _dl_profile_fixup
+ }
+ ADDLI_PTR r28, sp, FRAME_STACKFRAME
+ LD_PTR r28, r28
+ BGTZ r28, 1f
+ .else
+ {
+ move r0, r28 /* tpnt value 1 */
+ move r1, r29 /* PLT index 2 */
+ }
+ jal _dl_fixup
+ .endif
+ {
+ /* Copy aside the return value so we can restore r0 below. */
+ move r29, r0
+ /* Set up r27 to let us start restoring registers. */
+ ADDLI_PTR r27, sp, FRAME_REGS
+ }
+ FOR_EACH_REG(RESTORE)
+ .if \profile
+ ADDLI_PTR r28, sp, FRAME_STACKFRAME
+ LD r28, r28
+ BGTZ r28, 1f
+ .endif
+ {
+ /* Restore original user return address. */
+ LD lr, r27
+ /* Pop off our stack frame. */
+ ADDLI_PTR sp, sp, \framesize
+ }
+ cfi_def_cfa_offset (0)
+ jr r29 /* Transfer control to freshly loaded code. */
+ jrp lr /* Keep backtracer happy. */
+
+ .if \profile
+1: jalr r29 /* Call resolved function. */
+ {
+ ADDLI_PTR r28, sp, FRAME_TPNT
+ ADDLI_PTR r27, sp, FRAME_RETVAL
+ }
+ FOR_EACH_REG(SAVE)
+ {
+ LD r0, r28
+ ADDI_PTR r28, r28, FRAME_INDEX - FRAME_TPNT
+ }
+ {
+ LD r1, r28
+ ADDLI_PTR r2, sp, FRAME_REGS
+ }
+ {
+ ADDLI_PTR r3, sp, FRAME_RETVAL
+ jal _dl_call_pltexit
+ }
+ {
+ ADDLI_PTR lr, sp, FRAME_LR
+ ADDLI_PTR r27, sp, FRAME_RETVAL
+ }
+ FOR_EACH_REG(RESTORE)
+ {
+ LD lr, lr
+ ADDLI_PTR sp, sp, \framesize
+ }
+ jrp lr
+ .endif
+END (\name)
+ .endm
+
+ dl_resolve _dl_runtime_resolve, 0, FRAME_SIZE_SMALL
+#ifndef PROF
+ dl_resolve _dl_runtime_profile, 1, FRAME_SIZE_LARGE
+#endif