|  | /* Copyright (C) 2011-2016 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 |