1 /*- 2 * SPDX-License-Identifier: BSD-1-Clause 3 * 4 * Copyright 2012 Konstantin Belousov <kib@FreeBSD.org> 5 * Copyright (c) 2018, 2023 The FreeBSD Foundation 6 * 7 * Parts of this software was developed by Konstantin Belousov 8 * <kib@FreeBSD.org> under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/elf.h> 30 #include <sys/elf_common.h> 31 #include <errno.h> 32 #include <stdlib.h> 33 #include "libc_private.h" 34 35 extern void (*__preinit_array_start[])(int, char **, char **) __hidden; 36 extern void (*__preinit_array_end[])(int, char **, char **) __hidden; 37 extern void (*__init_array_start[])(int, char **, char **) __hidden; 38 extern void (*__init_array_end[])(int, char **, char **) __hidden; 39 extern void (*__fini_array_start[])(void) __hidden; 40 extern void (*__fini_array_end[])(void) __hidden; 41 extern void _fini(void) __hidden; 42 extern void _init(void) __hidden; 43 44 extern int _DYNAMIC; 45 #pragma weak _DYNAMIC 46 47 #if defined(CRT_IRELOC_RELA) 48 extern const Elf_Rela __rela_iplt_start[] __weak_symbol __hidden; 49 extern const Elf_Rela __rela_iplt_end[] __weak_symbol __hidden; 50 51 #include "reloc.c" 52 53 static void 54 process_irelocs(void) 55 { 56 const Elf_Rela *r; 57 58 for (r = &__rela_iplt_start[0]; r < &__rela_iplt_end[0]; r++) 59 crt1_handle_rela(r); 60 } 61 #elif defined(CRT_IRELOC_REL) 62 extern const Elf_Rel __rel_iplt_start[] __weak_symbol __hidden; 63 extern const Elf_Rel __rel_iplt_end[] __weak_symbol __hidden; 64 65 #include "reloc.c" 66 67 static void 68 process_irelocs(void) 69 { 70 const Elf_Rel *r; 71 72 for (r = &__rel_iplt_start[0]; r < &__rel_iplt_end[0]; r++) 73 crt1_handle_rel(r); 74 } 75 #elif defined(CRT_IRELOC_SUPPRESS) 76 #else 77 #error "Define platform reloc type" 78 #endif 79 80 #ifndef PIC 81 static void 82 finalizer(void) 83 { 84 void (*fn)(void); 85 size_t array_size, n; 86 87 array_size = __fini_array_end - __fini_array_start; 88 for (n = array_size; n > 0; n--) { 89 fn = __fini_array_start[n - 1]; 90 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 91 (fn)(); 92 } 93 _fini(); 94 } 95 #endif 96 97 static void 98 handle_static_init(int argc, char **argv, char **env) 99 { 100 #ifndef PIC 101 void (*fn)(int, char **, char **); 102 size_t array_size, n; 103 104 if (&_DYNAMIC != NULL) 105 return; 106 107 atexit(finalizer); 108 109 array_size = __preinit_array_end - __preinit_array_start; 110 for (n = 0; n < array_size; n++) { 111 fn = __preinit_array_start[n]; 112 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 113 fn(argc, argv, env); 114 } 115 _init(); 116 array_size = __init_array_end - __init_array_start; 117 for (n = 0; n < array_size; n++) { 118 fn = __init_array_start[n]; 119 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 120 fn(argc, argv, env); 121 } 122 #endif 123 } 124 125 static void 126 handle_argv(int argc, char *argv[], char **env) 127 { 128 const char *s; 129 130 if (environ == NULL) 131 environ = env; 132 if (argc > 0 && argv[0] != NULL) { 133 __progname = argv[0]; 134 for (s = __progname; *s != '\0'; s++) { 135 if (*s == '/') 136 __progname = s + 1; 137 } 138 } 139 } 140 141 static void 142 handle_irelocs(char *env[]) 143 { 144 #ifndef CRT_IRELOC_SUPPRESS 145 const Elf_Auxinfo *aux; 146 147 /* Find the auxiliary vector on the stack. */ 148 while (*env++ != 0) /* Skip over environment, and NULL terminator */ 149 ; 150 aux = (const Elf_Auxinfo *)env; 151 152 ifunc_init(aux); 153 process_irelocs(); 154 #else 155 (void)env; 156 #endif 157 } 158 159 void 160 __libc_start1(int argc, char *argv[], char *env[], void (*cleanup)(void), 161 int (*mainX)(int, char *[], char *[])) 162 { 163 handle_argv(argc, argv, env); 164 165 if (&_DYNAMIC != NULL) { 166 atexit(cleanup); 167 } else { 168 handle_irelocs(env); 169 _init_tls(); 170 } 171 172 handle_static_init(argc, argv, env); 173 174 /* 175 * C17 4.3 paragraph 3: 176 * The value of errno in the initial thread is zero at program 177 * startup. 178 */ 179 errno = 0; 180 exit(mainX(argc, argv, env)); 181 } 182 183 /* XXXKIB _mcleanup and monstartup defs */ 184 extern void _mcleanup(void); 185 extern void monstartup(void *, void *); 186 187 void 188 __libc_start1_gcrt(int argc, char *argv[], char *env[], 189 void (*cleanup)(void), int (*mainX)(int, char *[], char *[]), 190 int *eprolp, int *etextp) 191 { 192 handle_argv(argc, argv, env); 193 194 if (&_DYNAMIC != NULL) { 195 atexit(cleanup); 196 } else { 197 handle_irelocs(env); 198 _init_tls(); 199 } 200 201 atexit(_mcleanup); 202 monstartup(eprolp, etextp); 203 204 handle_static_init(argc, argv, env); 205 errno = 0; 206 exit(mainX(argc, argv, env)); 207 } 208