/* Copyright (C) 2011-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Chris Metcalf , 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 . */ #include #include /* 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