194 lines
4.8 KiB
ArmAsm
194 lines
4.8 KiB
ArmAsm
/* Copyright (C) 2011-2013 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
|