blob: 7a4914ef6e1e9de96c7396e8c824f74753fd2b61 [file] [log] [blame]
/* Copyright (C) 2011-2014 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