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 <stdlib.h> 32 #include "libc_private.h" 33 34 extern void (*__preinit_array_start[])(int, char **, char **) __hidden; 35 extern void (*__preinit_array_end[])(int, char **, char **) __hidden; 36 extern void (*__init_array_start[])(int, char **, char **) __hidden; 37 extern void (*__init_array_end[])(int, char **, char **) __hidden; 38 extern void (*__fini_array_start[])(void) __hidden; 39 extern void (*__fini_array_end[])(void) __hidden; 40 extern void _fini(void) __hidden; 41 extern void _init(void) __hidden; 42 43 extern int _DYNAMIC; 44 #pragma weak _DYNAMIC 45 46 #if defined(CRT_IRELOC_RELA) 47 extern const Elf_Rela __rela_iplt_start[] __weak_symbol __hidden; 48 extern const Elf_Rela __rela_iplt_end[] __weak_symbol __hidden; 49 50 #include "reloc.c" 51 52 static void 53 process_irelocs(void) 54 { 55 const Elf_Rela *r; 56 57 for (r = &__rela_iplt_start[0]; r < &__rela_iplt_end[0]; r++) 58 crt1_handle_rela(r); 59 } 60 #elif defined(CRT_IRELOC_REL) 61 extern const Elf_Rel __rel_iplt_start[] __weak_symbol __hidden; 62 extern const Elf_Rel __rel_iplt_end[] __weak_symbol __hidden; 63 64 #include "reloc.c" 65 66 static void 67 process_irelocs(void) 68 { 69 const Elf_Rel *r; 70 71 for (r = &__rel_iplt_start[0]; r < &__rel_iplt_end[0]; r++) 72 crt1_handle_rel(r); 73 } 74 #elif defined(CRT_IRELOC_SUPPRESS) 75 #else 76 #error "Define platform reloc type" 77 #endif 78 79 #ifndef PIC 80 static void 81 finalizer(void) 82 { 83 void (*fn)(void); 84 size_t array_size, n; 85 86 array_size = __fini_array_end - __fini_array_start; 87 for (n = array_size; n > 0; n--) { 88 fn = __fini_array_start[n - 1]; 89 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 90 (fn)(); 91 } 92 _fini(); 93 } 94 #endif 95 96 static void 97 handle_static_init(int argc, char **argv, char **env) 98 { 99 #ifndef PIC 100 void (*fn)(int, char **, char **); 101 size_t array_size, n; 102 103 if (&_DYNAMIC != NULL) 104 return; 105 106 atexit(finalizer); 107 108 array_size = __preinit_array_end - __preinit_array_start; 109 for (n = 0; n < array_size; n++) { 110 fn = __preinit_array_start[n]; 111 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 112 fn(argc, argv, env); 113 } 114 _init(); 115 array_size = __init_array_end - __init_array_start; 116 for (n = 0; n < array_size; n++) { 117 fn = __init_array_start[n]; 118 if ((uintptr_t)fn != 0 && (uintptr_t)fn != 1) 119 fn(argc, argv, env); 120 } 121 #endif 122 } 123 124 static void 125 handle_argv(int argc, char *argv[], char **env) 126 { 127 const char *s; 128 129 if (environ == NULL) 130 environ = env; 131 if (argc > 0 && argv[0] != NULL) { 132 __progname = argv[0]; 133 for (s = __progname; *s != '\0'; s++) { 134 if (*s == '/') 135 __progname = s + 1; 136 } 137 } 138 } 139 140 static void 141 handle_irelocs(char *env[]) 142 { 143 #ifndef CRT_IRELOC_SUPPRESS 144 const Elf_Auxinfo *aux; 145 146 /* Find the auxiliary vector on the stack. */ 147 while (*env++ != 0) /* Skip over environment, and NULL terminator */ 148 ; 149 aux = (const Elf_Auxinfo *)env; 150 151 ifunc_init(aux); 152 process_irelocs(); 153 #else 154 (void)env; 155 #endif 156 } 157 158 void 159 __libc_start1(int argc, char *argv[], char *env[], void (*cleanup)(void), 160 int (*mainX)(int, char *[], char *[])) 161 { 162 handle_argv(argc, argv, env); 163 164 if (&_DYNAMIC != NULL) { 165 atexit(cleanup); 166 } else { 167 handle_irelocs(env); 168 _init_tls(); 169 } 170 171 handle_static_init(argc, argv, env); 172 exit(mainX(argc, argv, env)); 173 } 174 175 /* XXXKIB _mcleanup and monstartup defs */ 176 extern void _mcleanup(void); 177 extern void monstartup(void *, void *); 178 179 void 180 __libc_start1_gcrt(int argc, char *argv[], char *env[], 181 void (*cleanup)(void), int (*mainX)(int, char *[], char *[]), 182 int *eprolp, int *etextp) 183 { 184 handle_argv(argc, argv, env); 185 186 if (&_DYNAMIC != NULL) { 187 atexit(cleanup); 188 } else { 189 handle_irelocs(env); 190 _init_tls(); 191 } 192 193 atexit(_mcleanup); 194 monstartup(eprolp, etextp); 195 196 handle_static_init(argc, argv, env); 197 exit(mainX(argc, argv, env)); 198 } 199