xref: /freebsd/libexec/rtld-elf/aarch64/rtld_start.S (revision 960f40b892cf15961f059f509990652555db7b4f)
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