1047c6e3aSAndrew Turner/*- 2047c6e3aSAndrew Turner * Copyright (c) 2014 The FreeBSD Foundation 3047c6e3aSAndrew Turner * 4047c6e3aSAndrew Turner * This software was developed by Andrew Turner under 5047c6e3aSAndrew Turner * sponsorship from the FreeBSD Foundation. 6047c6e3aSAndrew Turner * 7047c6e3aSAndrew Turner * Redistribution and use in source and binary forms, with or without 8047c6e3aSAndrew Turner * modification, are permitted provided that the following conditions 9047c6e3aSAndrew Turner * are met: 10047c6e3aSAndrew Turner * 1. Redistributions of source code must retain the above copyright 11047c6e3aSAndrew Turner * notice, this list of conditions and the following disclaimer. 12047c6e3aSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 13047c6e3aSAndrew Turner * notice, this list of conditions and the following disclaimer in the 14047c6e3aSAndrew Turner * documentation and/or other materials provided with the distribution. 15047c6e3aSAndrew Turner * 16047c6e3aSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17047c6e3aSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18047c6e3aSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19047c6e3aSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20047c6e3aSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21047c6e3aSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22047c6e3aSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23047c6e3aSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24047c6e3aSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25047c6e3aSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26047c6e3aSAndrew Turner * SUCH DAMAGE. 27047c6e3aSAndrew Turner */ 28047c6e3aSAndrew Turner 29047c6e3aSAndrew Turner#include <machine/asm.h> 305270cc97SAndrew Turner#include <sys/elf_common.h> 315270cc97SAndrew Turner 32047c6e3aSAndrew TurnerENTRY(.rtld_start) 33ac7759f5SDmitry Chagin .cfi_undefined x30 34047c6e3aSAndrew Turner mov x19, x0 /* Put ps_strings in a callee-saved register */ 35047c6e3aSAndrew Turner 36fafb1ee7SAndrew Turner sub sp, sp, #16 /* Make room for obj_main & exit proc */ 37ac7759f5SDmitry Chagin .cfi_adjust_cfa_offset 16 3865706c12SAndrew Turner 39047c6e3aSAndrew Turner mov x1, sp /* exit_proc */ 40047c6e3aSAndrew Turner add x2, x1, #8 /* obj_main */ 41047c6e3aSAndrew Turner bl _rtld /* Call the loader */ 42047c6e3aSAndrew Turner mov x8, x0 /* Backup the entry point */ 435645dfb4SDmitry Chagin ldp x2, x1, [sp], #16 /* Load cleanup, obj_main */ 44ac7759f5SDmitry Chagin .cfi_adjust_cfa_offset 0 45047c6e3aSAndrew Turner 46047c6e3aSAndrew Turner mov x0, x19 /* Restore ps_strings */ 47047c6e3aSAndrew Turner br x8 /* Jump to the entry point */ 48047c6e3aSAndrew TurnerEND(.rtld_start) 49047c6e3aSAndrew Turner 50047c6e3aSAndrew Turner/* 51047c6e3aSAndrew Turner * sp + 0 = &GOT[x + 3] 52047c6e3aSAndrew Turner * sp + 8 = RA 53047c6e3aSAndrew Turner * x16 = &GOT[2] 54047c6e3aSAndrew Turner * x17 = &_rtld_bind_start 55047c6e3aSAndrew Turner */ 56047c6e3aSAndrew TurnerENTRY(_rtld_bind_start) 57047c6e3aSAndrew Turner mov x17, sp 58047c6e3aSAndrew Turner 59fad101b3SMichal Meloun /* Save frame pointer and SP */ 60fad101b3SMichal Meloun stp x29, x30, [sp, #-16]! 61fad101b3SMichal Meloun mov x29, sp 62fad101b3SMichal Meloun .cfi_def_cfa x29, 16 63fad101b3SMichal Meloun .cfi_offset x30, -8 64fad101b3SMichal Meloun .cfi_offset x29, -16 65fad101b3SMichal Meloun 66047c6e3aSAndrew Turner /* Save the arguments */ 67047c6e3aSAndrew Turner stp x0, x1, [sp, #-16]! 68047c6e3aSAndrew Turner stp x2, x3, [sp, #-16]! 69047c6e3aSAndrew Turner stp x4, x5, [sp, #-16]! 70047c6e3aSAndrew Turner stp x6, x7, [sp, #-16]! 71ff8a3cb6SAndrew Turner stp x8, xzr, [sp, #-16]! 72047c6e3aSAndrew Turner 73aeb8eeb5SAndrew Turner /* Save any floating-point arguments */ 74aeb8eeb5SAndrew Turner stp q0, q1, [sp, #-32]! 75aeb8eeb5SAndrew Turner stp q2, q3, [sp, #-32]! 76aeb8eeb5SAndrew Turner stp q4, q5, [sp, #-32]! 77aeb8eeb5SAndrew Turner stp q6, q7, [sp, #-32]! 78aeb8eeb5SAndrew Turner 79047c6e3aSAndrew Turner /* Calculate reloff */ 80047c6e3aSAndrew Turner ldr x2, [x17, #0] /* Get the address of the entry */ 81047c6e3aSAndrew Turner sub x1, x2, x16 /* Find its offset */ 82047c6e3aSAndrew Turner sub x1, x1, #8 /* Adjust for x16 not being at offset 0 */ 83047c6e3aSAndrew Turner /* Each rela item has 3 entriesso we need reloff = 3 * index */ 84047c6e3aSAndrew Turner lsl x3, x1, #1 /* x3 = 2 * offset */ 85047c6e3aSAndrew Turner add x1, x1, x3 /* x1 = x3 + offset = 3 * offset */ 86047c6e3aSAndrew Turner 87047c6e3aSAndrew Turner /* Load obj */ 88047c6e3aSAndrew Turner ldr x0, [x16, #-8] 89047c6e3aSAndrew Turner 90047c6e3aSAndrew Turner /* Call into rtld */ 91047c6e3aSAndrew Turner bl _rtld_bind 92047c6e3aSAndrew Turner 93047c6e3aSAndrew Turner /* Backup the address to branch to */ 94047c6e3aSAndrew Turner mov x16, x0 95047c6e3aSAndrew Turner 96047c6e3aSAndrew Turner /* restore the arguments */ 97aeb8eeb5SAndrew Turner ldp q6, q7, [sp], #32 98aeb8eeb5SAndrew Turner ldp q4, q5, [sp], #32 99aeb8eeb5SAndrew Turner ldp q2, q3, [sp], #32 100aeb8eeb5SAndrew Turner ldp q0, q1, [sp], #32 101ff8a3cb6SAndrew Turner ldp x8, xzr, [sp], #16 102047c6e3aSAndrew Turner ldp x6, x7, [sp], #16 103047c6e3aSAndrew Turner ldp x4, x5, [sp], #16 104047c6e3aSAndrew Turner ldp x2, x3, [sp], #16 105047c6e3aSAndrew Turner ldp x0, x1, [sp], #16 106fad101b3SMichal Meloun 107fad101b3SMichal Meloun /* Restore frame pointer */ 108fad101b3SMichal Meloun ldp x29, xzr, [sp], #16 109fad101b3SMichal Meloun 110fad101b3SMichal Meloun /* Restore link register saved by the plt code */ 111fad101b3SMichal Meloun ldp xzr, x30, [sp], #16 112047c6e3aSAndrew Turner 113047c6e3aSAndrew Turner /* Call into the correct function */ 114047c6e3aSAndrew Turner br x16 115047c6e3aSAndrew TurnerEND(_rtld_bind_start) 116047c6e3aSAndrew Turner 117047c6e3aSAndrew Turner/* 1184849c3a5SMichal Meloun * struct rel_tlsdesc { 1194849c3a5SMichal Meloun * uint64_t resolver_fnc; 1204849c3a5SMichal Meloun * uint64_t resolver_arg; 121047c6e3aSAndrew Turner * 122047c6e3aSAndrew Turner * 1234849c3a5SMichal Meloun * uint64_t _rtld_tlsdesc_static(struct rel_tlsdesc *); 1244849c3a5SMichal Meloun * 1254849c3a5SMichal Meloun * Resolver function for TLS symbols resolved at load time 126047c6e3aSAndrew Turner */ 1274849c3a5SMichal MelounENTRY(_rtld_tlsdesc_static) 128047c6e3aSAndrew Turner ldr x0, [x0, #8] 129a97120d6SAndrew Turner ret 1304849c3a5SMichal MelounEND(_rtld_tlsdesc_static) 131a97120d6SAndrew Turner 132a97120d6SAndrew Turner/* 1334849c3a5SMichal Meloun * uint64_t _rtld_tlsdesc_undef(void); 134a97120d6SAndrew Turner * 1354849c3a5SMichal Meloun * Resolver function for weak and undefined TLS symbols 1364849c3a5SMichal Meloun */ 1374849c3a5SMichal MelounENTRY(_rtld_tlsdesc_undef) 1384849c3a5SMichal Meloun str x1, [sp, #-16]! 1394849c3a5SMichal Meloun .cfi_adjust_cfa_offset 16 1404849c3a5SMichal Meloun 1414849c3a5SMichal Meloun mrs x1, tpidr_el0 1424849c3a5SMichal Meloun ldr x0, [x0, #8] 1434849c3a5SMichal Meloun sub x0, x0, x1 1444849c3a5SMichal Meloun 1454849c3a5SMichal Meloun ldr x1, [sp], #16 1464849c3a5SMichal Meloun .cfi_adjust_cfa_offset -16 1474849c3a5SMichal Meloun ret 1484849c3a5SMichal MelounEND(_rtld_tlsdesc_undef) 1494849c3a5SMichal Meloun 1504849c3a5SMichal Meloun/* 1514849c3a5SMichal Meloun * uint64_t _rtld_tlsdesc_dynamic(struct rel_tlsdesc *); 1524849c3a5SMichal Meloun * 1534849c3a5SMichal Meloun * Resolver function for TLS symbols from dlopen() 154a97120d6SAndrew Turner */ 155a97120d6SAndrew TurnerENTRY(_rtld_tlsdesc_dynamic) 1564849c3a5SMichal Meloun /* Save registers used in fast path */ 1574849c3a5SMichal Meloun stp x1, x2, [sp, #(-2 * 16)]! 1584849c3a5SMichal Meloun stp x3, x4, [sp, #(1 * 16)] 1594849c3a5SMichal Meloun .cfi_adjust_cfa_offset 2 * 16 1604849c3a5SMichal Meloun .cfi_rel_offset x1, 0 1614849c3a5SMichal Meloun .cfi_rel_offset x2, 8 1624849c3a5SMichal Meloun .cfi_rel_offset x3, 16 1634849c3a5SMichal Meloun .cfi_rel_offset x4, 24 1644849c3a5SMichal Meloun 1654849c3a5SMichal Meloun /* Test fastpath - inlined version of tls_get_addr_common(). */ 1664849c3a5SMichal Meloun ldr x1, [x0, #8] /* tlsdesc ptr */ 1674849c3a5SMichal Meloun mrs x4, tpidr_el0 1684849c3a5SMichal Meloun ldr x0, [x4] /* DTV pointer */ 1694849c3a5SMichal Meloun ldr x2, [x0] /* dtv[0] (generation count) */ 1704849c3a5SMichal Meloun ldr x3, [x1] /* tlsdec->dtv_gen */ 1714849c3a5SMichal Meloun cmp x2, x3 1724849c3a5SMichal Meloun b.ne 1f /* dtv[0] != tlsdec->dtv_gen */ 1734849c3a5SMichal Meloun 1744849c3a5SMichal Meloun ldr w2, [x1, #8] /* tlsdec->tls_index */ 1754849c3a5SMichal Meloun add w2, w2, #1 1764849c3a5SMichal Meloun ldr x3, [x0, w2, sxtw #3] /* dtv[tlsdesc->tls_index + 1] */ 1774849c3a5SMichal Meloun cbz x3, 1f 1784849c3a5SMichal Meloun 1794849c3a5SMichal Meloun /* Return (dtv[tlsdesc->tls_index + 1] + tlsdesc->tls_offs - tp) */ 1804849c3a5SMichal Meloun ldr x2, [x1, #16] /* tlsdec->tls_offs */ 1814849c3a5SMichal Meloun add x2, x2, x3 1824849c3a5SMichal Meloun sub x0, x2, x4 1834849c3a5SMichal Meloun /* Restore registers and return */ 1844849c3a5SMichal Meloun ldp x3, x4, [sp, #(1 * 16)] 1854849c3a5SMichal Meloun ldp x1, x2, [sp], #(2 * 16) 1864849c3a5SMichal Meloun .cfi_adjust_cfa_offset -2 * 16 1874849c3a5SMichal Meloun ret 1884849c3a5SMichal Meloun 1894849c3a5SMichal Meloun /* 1904849c3a5SMichal Meloun * Slow path 1914849c3a5SMichal Meloun * return( 192*960f40b8SJessica Clarke * tls_get_addr_common(tcb, tlsdesc->tls_index, tlsdesc->tls_offs)); 1934849c3a5SMichal Meloun * 1944849c3a5SMichal Meloun */ 1954849c3a5SMichal Meloun1: 1963576233cSGordon Bergling /* Save all integer registers */ 1974849c3a5SMichal Meloun stp x29, x30, [sp, #-(8 * 16)]! 1984849c3a5SMichal Meloun .cfi_adjust_cfa_offset 8 * 16 1994849c3a5SMichal Meloun .cfi_rel_offset x29, 0 2004849c3a5SMichal Meloun .cfi_rel_offset x30, 8 2014849c3a5SMichal Meloun 202a97120d6SAndrew Turner mov x29, sp 2034849c3a5SMichal Meloun stp x5, x6, [sp, #(1 * 16)] 2044849c3a5SMichal Meloun stp x7, x8, [sp, #(2 * 16)] 2054849c3a5SMichal Meloun stp x9, x10, [sp, #(3 * 16)] 2064849c3a5SMichal Meloun stp x11, x12, [sp, #(4 * 16)] 2074849c3a5SMichal Meloun stp x13, x14, [sp, #(5 * 16)] 2084849c3a5SMichal Meloun stp x15, x16, [sp, #(6 * 16)] 2094849c3a5SMichal Meloun stp x17, x18, [sp, #(7 * 16)] 2104849c3a5SMichal Meloun .cfi_rel_offset x5, 16 2114849c3a5SMichal Meloun .cfi_rel_offset x6, 24 2124849c3a5SMichal Meloun .cfi_rel_offset x7, 32 2134849c3a5SMichal Meloun .cfi_rel_offset x8, 40 2144849c3a5SMichal Meloun .cfi_rel_offset x9, 48 2154849c3a5SMichal Meloun .cfi_rel_offset x10, 56 2164849c3a5SMichal Meloun .cfi_rel_offset x11, 64 2174849c3a5SMichal Meloun .cfi_rel_offset x12, 72 2184849c3a5SMichal Meloun .cfi_rel_offset x13, 80 2194849c3a5SMichal Meloun .cfi_rel_offset x14, 88 2204849c3a5SMichal Meloun .cfi_rel_offset x15, 96 2214849c3a5SMichal Meloun .cfi_rel_offset x16, 104 2224849c3a5SMichal Meloun .cfi_rel_offset x17, 112 2234849c3a5SMichal Meloun .cfi_rel_offset x18, 120 224a97120d6SAndrew Turner 225a97120d6SAndrew Turner /* Find the tls offset */ 226*960f40b8SJessica Clarke mov x0, x4 /* tcb */ 2274849c3a5SMichal Meloun mov x3, x1 /* tlsdesc ptr */ 2284849c3a5SMichal Meloun ldr w1, [x3, #8] /* tlsdec->tls_index */ 2294849c3a5SMichal Meloun ldr x2, [x3, #16] /* tlsdec->tls_offs */ 2304849c3a5SMichal Meloun bl tls_get_addr_common 2314849c3a5SMichal Meloun mrs x1, tpidr_el0 2324849c3a5SMichal Meloun sub x0, x0, x1 233a97120d6SAndrew Turner 2344849c3a5SMichal Meloun /* Restore slow patch registers */ 2354849c3a5SMichal Meloun ldp x17, x18, [sp, #(7 * 16)] 2364849c3a5SMichal Meloun ldp x15, x16, [sp, #(6 * 16)] 2374849c3a5SMichal Meloun ldp x13, x14, [sp, #(5 * 16)] 2384849c3a5SMichal Meloun ldp x11, x12, [sp, #(4 * 16)] 2394849c3a5SMichal Meloun ldp x9, x10, [sp, #(3 * 16)] 2404849c3a5SMichal Meloun ldp x7, x8, [sp, #(2 * 16)] 2414849c3a5SMichal Meloun ldp x5, x6, [sp, #(1 * 16)] 2424849c3a5SMichal Meloun ldp x29, x30, [sp], #(8 * 16) 2434849c3a5SMichal Meloun .cfi_adjust_cfa_offset -8 * 16 2444849c3a5SMichal Meloun .cfi_restore x29 2454849c3a5SMichal Meloun .cfi_restore x30 246a97120d6SAndrew Turner 2474849c3a5SMichal Meloun /* Restore fast path registers and return */ 2484849c3a5SMichal Meloun ldp x3, x4, [sp, #16] 2494849c3a5SMichal Meloun ldp x1, x2, [sp], #(2 * 16) 2504849c3a5SMichal Meloun .cfi_adjust_cfa_offset -2 * 16 251a97120d6SAndrew Turner ret 252a97120d6SAndrew TurnerEND(_rtld_tlsdesc_dynamic) 2535270cc97SAndrew Turner 2545270cc97SAndrew TurnerGNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL) 255