| /* 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 |