1*6beeb802Sskrll /* $NetBSD: crt0-common.c,v 1.27 2022/06/21 06:52:17 skrll Exp $ */
201bc9d50Sjoerg
301bc9d50Sjoerg /*
401bc9d50Sjoerg * Copyright (c) 1998 Christos Zoulas
501bc9d50Sjoerg * Copyright (c) 1995 Christopher G. Demetriou
601bc9d50Sjoerg * All rights reserved.
701bc9d50Sjoerg *
801bc9d50Sjoerg * Redistribution and use in source and binary forms, with or without
901bc9d50Sjoerg * modification, are permitted provided that the following conditions
1001bc9d50Sjoerg * are met:
1101bc9d50Sjoerg * 1. Redistributions of source code must retain the above copyright
1201bc9d50Sjoerg * notice, this list of conditions and the following disclaimer.
1301bc9d50Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1401bc9d50Sjoerg * notice, this list of conditions and the following disclaimer in the
1501bc9d50Sjoerg * documentation and/or other materials provided with the distribution.
1601bc9d50Sjoerg * 3. All advertising materials mentioning features or use of this software
1701bc9d50Sjoerg * must display the following acknowledgement:
1801bc9d50Sjoerg * This product includes software developed for the
1901bc9d50Sjoerg * NetBSD Project. See http://www.NetBSD.org/ for
2001bc9d50Sjoerg * information about NetBSD.
2101bc9d50Sjoerg * 4. The name of the author may not be used to endorse or promote products
2201bc9d50Sjoerg * derived from this software without specific prior written permission.
2301bc9d50Sjoerg *
2401bc9d50Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2501bc9d50Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2601bc9d50Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2701bc9d50Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2801bc9d50Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2901bc9d50Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3001bc9d50Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3101bc9d50Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3201bc9d50Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3301bc9d50Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3401bc9d50Sjoerg *
3501bc9d50Sjoerg * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
3601bc9d50Sjoerg */
3701bc9d50Sjoerg
3801bc9d50Sjoerg #include <sys/cdefs.h>
39*6beeb802Sskrll __RCSID("$NetBSD: crt0-common.c,v 1.27 2022/06/21 06:52:17 skrll Exp $");
4001bc9d50Sjoerg
4101bc9d50Sjoerg #include <sys/types.h>
42e4a3eddeSjoerg #include <sys/exec.h>
437acd15a3Sjoerg #include <sys/exec_elf.h>
4401bc9d50Sjoerg #include <sys/syscall.h>
4501bc9d50Sjoerg #include <machine/profile.h>
4601bc9d50Sjoerg #include <stdlib.h>
4701bc9d50Sjoerg #include <unistd.h>
4801bc9d50Sjoerg
495bd02060Schristos #include "csu-common.h"
505bd02060Schristos
5101bc9d50Sjoerg extern int main(int, char **, char **);
5201bc9d50Sjoerg
537acd15a3Sjoerg typedef void (*fptr_t)(void);
54d0ce0a99Schristos #ifndef HAVE_INITFINI_ARRAY
5501bc9d50Sjoerg extern void _init(void);
5601bc9d50Sjoerg extern void _fini(void);
5718b01b61Schristos #endif
58399a2aeaSjoerg extern void _libc_init(void);
5901bc9d50Sjoerg
6001bc9d50Sjoerg /*
6101bc9d50Sjoerg * Arrange for _DYNAMIC to be weak and undefined (and therefore to show up
6201bc9d50Sjoerg * as being at address zero, unless something else defines it). That way,
6301bc9d50Sjoerg * if we happen to be compiling without -static but with without any
6401bc9d50Sjoerg * shared libs present, things will still work.
6501bc9d50Sjoerg */
6626b475b1Sjoerg
67ed49abf5Sjoerg __weakref_visible int rtld_DYNAMIC __weak_reference(_DYNAMIC);
6801bc9d50Sjoerg
6901bc9d50Sjoerg #ifdef MCRT0
7001bc9d50Sjoerg extern void monstartup(u_long, u_long);
7101bc9d50Sjoerg extern void _mcleanup(void);
7201bc9d50Sjoerg extern unsigned char __etext, __eprol;
7301bc9d50Sjoerg #endif /* MCRT0 */
7401bc9d50Sjoerg
7501bc9d50Sjoerg static char empty_string[] = "";
765bd02060Schristos
775bd02060Schristos char **environ __common;
785bd02060Schristos struct ps_strings *__ps_strings __common = 0;
795bd02060Schristos char *__progname __common = empty_string;
8001bc9d50Sjoerg
817acd15a3Sjoerg __dead __dso_hidden void ___start(void (*)(void), struct ps_strings *);
8201bc9d50Sjoerg
8301bc9d50Sjoerg #define write(fd, s, n) __syscall(SYS_write, (fd), (s), (n))
8401bc9d50Sjoerg
8501bc9d50Sjoerg #define _FATAL(str) \
8601bc9d50Sjoerg do { \
8701bc9d50Sjoerg write(2, str, sizeof(str)-1); \
8801bc9d50Sjoerg _exit(1); \
8901bc9d50Sjoerg } while (0)
9001bc9d50Sjoerg
91e079cdf7Smatt /*
92e079cdf7Smatt * If we are using INIT_ARRAY/FINI_ARRAY and we are linked statically,
93e079cdf7Smatt * we have to process these instead of relying on RTLD to do it for us.
94e079cdf7Smatt *
95e079cdf7Smatt * Since we don't need .init or .fini sections, just code them in C
96e079cdf7Smatt * to make life easier.
97e079cdf7Smatt */
986d2eb438Sjoerg extern const fptr_t __preinit_array_start[] __dso_hidden;
996d2eb438Sjoerg extern const fptr_t __preinit_array_end[] __dso_hidden __weak;
1006d2eb438Sjoerg extern const fptr_t __init_array_start[] __dso_hidden;
1016d2eb438Sjoerg extern const fptr_t __init_array_end[] __dso_hidden __weak;
1026d2eb438Sjoerg extern const fptr_t __fini_array_start[] __dso_hidden;
1036d2eb438Sjoerg extern const fptr_t __fini_array_end[] __dso_hidden __weak;
104e079cdf7Smatt
105e079cdf7Smatt static inline void
_preinit(void)10607af1b28Smatt _preinit(void)
10707af1b28Smatt {
1086d2eb438Sjoerg for (const fptr_t *f = __preinit_array_start; f < __preinit_array_end; f++) {
10907af1b28Smatt (*f)();
11007af1b28Smatt }
11107af1b28Smatt }
11207af1b28Smatt
11307af1b28Smatt static inline void
_initarray(void)114d0ce0a99Schristos _initarray(void)
115e079cdf7Smatt {
1166d2eb438Sjoerg for (const fptr_t *f = __init_array_start; f < __init_array_end; f++) {
117e079cdf7Smatt (*f)();
118e079cdf7Smatt }
119e079cdf7Smatt }
120e079cdf7Smatt
121e079cdf7Smatt static void
_finiarray(void)122d0ce0a99Schristos _finiarray(void)
123e079cdf7Smatt {
1246d2eb438Sjoerg for (const fptr_t *f = __fini_array_start; f < __fini_array_end; f++) {
125e079cdf7Smatt (*f)();
126e079cdf7Smatt }
127e079cdf7Smatt }
128e079cdf7Smatt
129450579d1Sskrll #if \
130*6beeb802Sskrll defined(__aarch64__) || \
131450579d1Sskrll defined(__powerpc__) || \
132450579d1Sskrll defined(__sparc__) || \
133450579d1Sskrll defined(__x86_64__)
1344ba63be7Sjoerg #define HAS_IPLTA
1354ba63be7Sjoerg static void fix_iplta(void) __noinline;
136450579d1Sskrll #elif \
137450579d1Sskrll defined(__arm__) || \
138450579d1Sskrll defined(__i386__)
1394ba63be7Sjoerg #define HAS_IPLT
1404ba63be7Sjoerg static void fix_iplt(void) __noinline;
1414ba63be7Sjoerg #endif
1424ba63be7Sjoerg
1434ba63be7Sjoerg
1444ba63be7Sjoerg #ifdef HAS_IPLTA
1454ba63be7Sjoerg #include <stdio.h>
1464ba63be7Sjoerg extern const Elf_Rela __rela_iplt_start[] __dso_hidden __weak;
1474ba63be7Sjoerg extern const Elf_Rela __rela_iplt_end[] __dso_hidden __weak;
148a0c0dc61Sjoerg #ifdef __sparc__
149a0c0dc61Sjoerg #define IFUNC_RELOCATION R_TYPE(JMP_IREL)
150a0c0dc61Sjoerg #include <machine/elf_support.h>
151a0c0dc61Sjoerg #define write_plt(where, value) sparc_write_branch((void *)where, (void *)value)
152a0c0dc61Sjoerg #else
153a0c0dc61Sjoerg #define IFUNC_RELOCATION R_TYPE(IRELATIVE)
154a0c0dc61Sjoerg #define write_plt(where, value) *where = value
155a0c0dc61Sjoerg #endif
1564ba63be7Sjoerg
1574ba63be7Sjoerg static void
fix_iplta(void)1584ba63be7Sjoerg fix_iplta(void)
1594ba63be7Sjoerg {
1604ba63be7Sjoerg const Elf_Rela *rela, *relalim;
1614ba63be7Sjoerg uintptr_t relocbase = 0;
1624ba63be7Sjoerg Elf_Addr *where, target;
1634ba63be7Sjoerg
1644ba63be7Sjoerg rela = __rela_iplt_start;
1654ba63be7Sjoerg relalim = __rela_iplt_end;
1664ba63be7Sjoerg for (; rela < relalim; ++rela) {
167a0c0dc61Sjoerg if (ELF_R_TYPE(rela->r_info) != IFUNC_RELOCATION)
1684ba63be7Sjoerg abort();
1694ba63be7Sjoerg where = (Elf_Addr *)(relocbase + rela->r_offset);
1704ba63be7Sjoerg target = (Elf_Addr)(relocbase + rela->r_addend);
1714ba63be7Sjoerg target = ((Elf_Addr(*)(void))target)();
172a0c0dc61Sjoerg write_plt(where, target);
1734ba63be7Sjoerg }
1744ba63be7Sjoerg }
1754ba63be7Sjoerg #endif
1764ba63be7Sjoerg #ifdef HAS_IPLT
1774ba63be7Sjoerg extern const Elf_Rel __rel_iplt_start[] __dso_hidden __weak;
1784ba63be7Sjoerg extern const Elf_Rel __rel_iplt_end[] __dso_hidden __weak;
179a0c0dc61Sjoerg #define IFUNC_RELOCATION R_TYPE(IRELATIVE)
1804ba63be7Sjoerg
1814ba63be7Sjoerg static void
fix_iplt(void)1824ba63be7Sjoerg fix_iplt(void)
1834ba63be7Sjoerg {
1844ba63be7Sjoerg const Elf_Rel *rel, *rellim;
1854ba63be7Sjoerg uintptr_t relocbase = 0;
1864ba63be7Sjoerg Elf_Addr *where, target;
1874ba63be7Sjoerg
1884ba63be7Sjoerg rel = __rel_iplt_start;
1894ba63be7Sjoerg rellim = __rel_iplt_end;
1904ba63be7Sjoerg for (; rel < rellim; ++rel) {
191a0c0dc61Sjoerg if (ELF_R_TYPE(rel->r_info) != IFUNC_RELOCATION)
1924ba63be7Sjoerg abort();
1934ba63be7Sjoerg where = (Elf_Addr *)(relocbase + rel->r_offset);
1944ba63be7Sjoerg target = ((Elf_Addr(*)(void))*where)();
1954ba63be7Sjoerg *where = target;
1964ba63be7Sjoerg }
1974ba63be7Sjoerg }
1984ba63be7Sjoerg #endif
1994ba63be7Sjoerg
20001a77a40Sjoerg #if defined(__x86_64__) || defined(__i386__)
20101a77a40Sjoerg # define HAS_RELOCATE_SELF
20201a77a40Sjoerg # if defined(__x86_64__)
20301a77a40Sjoerg # define RELA
20401a77a40Sjoerg # define REL_TAG DT_RELA
20501a77a40Sjoerg # define RELSZ_TAG DT_RELASZ
20601a77a40Sjoerg # define REL_TYPE Elf_Rela
20701a77a40Sjoerg # else
20801a77a40Sjoerg # define REL_TAG DT_REL
20901a77a40Sjoerg # define RELSZ_TAG DT_RELSZ
21001a77a40Sjoerg # define REL_TYPE Elf_Rel
21101a77a40Sjoerg # endif
21201a77a40Sjoerg
21301a77a40Sjoerg #include <elf.h>
21401a77a40Sjoerg
21501a77a40Sjoerg static void relocate_self(struct ps_strings *) __noinline;
21601a77a40Sjoerg
21701a77a40Sjoerg static void
relocate_self(struct ps_strings * ps_strings)21801a77a40Sjoerg relocate_self(struct ps_strings *ps_strings)
21901a77a40Sjoerg {
22001a77a40Sjoerg AuxInfo *aux = (AuxInfo *)(ps_strings->ps_argvstr + ps_strings->ps_nargvstr +
22101a77a40Sjoerg ps_strings->ps_nenvstr + 2);
2228d092b50Skre uintptr_t relocbase = (uintptr_t)~0U;
2238d092b50Skre const Elf_Phdr *phdr = NULL;
2248d092b50Skre Elf_Half phnum = (Elf_Half)~0;
22501a77a40Sjoerg
22601a77a40Sjoerg for (; aux->a_type != AT_NULL; ++aux) {
22701a77a40Sjoerg switch (aux->a_type) {
22801a77a40Sjoerg case AT_BASE:
22901a77a40Sjoerg if (aux->a_v)
23001a77a40Sjoerg return;
23101a77a40Sjoerg break;
23201a77a40Sjoerg case AT_PHDR:
23301a77a40Sjoerg phdr = (void *)aux->a_v;
23401a77a40Sjoerg break;
23501a77a40Sjoerg case AT_PHNUM:
23601a77a40Sjoerg phnum = (Elf_Half)aux->a_v;
23701a77a40Sjoerg break;
23801a77a40Sjoerg }
23901a77a40Sjoerg }
2408d092b50Skre
2418d092b50Skre if (phdr == NULL || phnum == (Elf_Half)~0)
2428d092b50Skre return;
2438d092b50Skre
2448d092b50Skre const Elf_Phdr *phlimit = phdr + phnum, *dynphdr = NULL;
24501a77a40Sjoerg
24601a77a40Sjoerg for (; phdr < phlimit; ++phdr) {
24701a77a40Sjoerg if (phdr->p_type == PT_DYNAMIC)
24801a77a40Sjoerg dynphdr = phdr;
24901a77a40Sjoerg if (phdr->p_type == PT_PHDR)
25001a77a40Sjoerg relocbase = (uintptr_t)phdr - phdr->p_vaddr;
25101a77a40Sjoerg }
2528d092b50Skre if (dynphdr == NULL || relocbase == (uintptr_t)~0U)
2538d092b50Skre return;
2548d092b50Skre
25501a77a40Sjoerg Elf_Dyn *dynp = (Elf_Dyn *)((uint8_t *)dynphdr->p_vaddr + relocbase);
25601a77a40Sjoerg
25701a77a40Sjoerg const REL_TYPE *relocs = 0, *relocslim;
25801a77a40Sjoerg Elf_Addr relocssz = 0;
25901a77a40Sjoerg
26001a77a40Sjoerg for (; dynp->d_tag != DT_NULL; dynp++) {
26101a77a40Sjoerg switch (dynp->d_tag) {
26201a77a40Sjoerg case REL_TAG:
26301a77a40Sjoerg relocs =
26401a77a40Sjoerg (const REL_TYPE *)(relocbase + dynp->d_un.d_ptr);
26501a77a40Sjoerg break;
26601a77a40Sjoerg case RELSZ_TAG:
26701a77a40Sjoerg relocssz = dynp->d_un.d_val;
26801a77a40Sjoerg break;
26901a77a40Sjoerg }
27001a77a40Sjoerg }
27101a77a40Sjoerg relocslim = (const REL_TYPE *)((const uint8_t *)relocs + relocssz);
27201a77a40Sjoerg for (; relocs < relocslim; ++relocs) {
27301a77a40Sjoerg Elf_Addr *where;
27401a77a40Sjoerg
27501a77a40Sjoerg where = (Elf_Addr *)(relocbase + relocs->r_offset);
27601a77a40Sjoerg
27701a77a40Sjoerg switch (ELF_R_TYPE(relocs->r_info)) {
27801a77a40Sjoerg case R_TYPE(RELATIVE): /* word64 B + A */
27901a77a40Sjoerg #ifdef RELA
28001a77a40Sjoerg *where = (Elf_Addr)(relocbase + relocs->r_addend);
28101a77a40Sjoerg #else
28201a77a40Sjoerg *where += (Elf_Addr)relocbase;
28301a77a40Sjoerg #endif
28401a77a40Sjoerg break;
28501a77a40Sjoerg #ifdef IFUNC_RELOCATION
28601a77a40Sjoerg case IFUNC_RELOCATION:
28701a77a40Sjoerg break;
28801a77a40Sjoerg #endif
28901a77a40Sjoerg default:
29001a77a40Sjoerg abort();
29101a77a40Sjoerg }
29201a77a40Sjoerg }
29301a77a40Sjoerg }
29401a77a40Sjoerg #endif
29501a77a40Sjoerg
29601bc9d50Sjoerg void
___start(void (* cleanup)(void),struct ps_strings * ps_strings)297e4a3eddeSjoerg ___start(void (*cleanup)(void), /* from shared loader */
29801bc9d50Sjoerg struct ps_strings *ps_strings)
29901bc9d50Sjoerg {
30001a77a40Sjoerg #if defined(HAS_RELOCATE_SELF)
30101a77a40Sjoerg relocate_self(ps_strings);
30201a77a40Sjoerg #endif
30301bc9d50Sjoerg
304e4a3eddeSjoerg if (ps_strings == NULL)
305e4a3eddeSjoerg _FATAL("ps_strings missing\n");
306e4a3eddeSjoerg __ps_strings = ps_strings;
307e4a3eddeSjoerg
308e4a3eddeSjoerg environ = ps_strings->ps_envstr;
309e4a3eddeSjoerg
310e4a3eddeSjoerg if (ps_strings->ps_argvstr[0] != NULL) {
31101bc9d50Sjoerg char *c;
312e4a3eddeSjoerg __progname = ps_strings->ps_argvstr[0];
313e4a3eddeSjoerg for (c = ps_strings->ps_argvstr[0]; *c; ++c) {
31401bc9d50Sjoerg if (*c == '/')
31501bc9d50Sjoerg __progname = c + 1;
31601bc9d50Sjoerg }
31701bc9d50Sjoerg } else {
31801bc9d50Sjoerg __progname = empty_string;
31901bc9d50Sjoerg }
32001bc9d50Sjoerg
3217acd15a3Sjoerg if (cleanup != NULL)
32201bc9d50Sjoerg atexit(cleanup);
32301bc9d50Sjoerg
324399a2aeaSjoerg _libc_init();
325399a2aeaSjoerg
3264ba63be7Sjoerg if (&rtld_DYNAMIC == NULL) {
3274ba63be7Sjoerg #ifdef HAS_IPLTA
3284ba63be7Sjoerg fix_iplta();
3294ba63be7Sjoerg #endif
3304ba63be7Sjoerg #ifdef HAS_IPLT
3314ba63be7Sjoerg fix_iplt();
3324ba63be7Sjoerg #endif
3334ba63be7Sjoerg }
3344ba63be7Sjoerg
33507af1b28Smatt _preinit();
33607af1b28Smatt
33701bc9d50Sjoerg #ifdef MCRT0
33801bc9d50Sjoerg atexit(_mcleanup);
33901bc9d50Sjoerg monstartup((u_long)&__eprol, (u_long)&__etext);
34001bc9d50Sjoerg #endif
34101bc9d50Sjoerg
342d0ce0a99Schristos atexit(_finiarray);
343d0ce0a99Schristos _initarray();
344d0ce0a99Schristos
345d0ce0a99Schristos #ifndef HAVE_INITFINI_ARRAY
34601bc9d50Sjoerg atexit(_fini);
34701bc9d50Sjoerg _init();
348d0ce0a99Schristos #endif
34901bc9d50Sjoerg
350e4a3eddeSjoerg exit(main(ps_strings->ps_nargvstr, ps_strings->ps_argvstr, environ));
35101bc9d50Sjoerg }
352