1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999 John D. Polstra
5 * Copyright (c) 1999,2001 Peter Wemm <peter@FreeBSD.org>
6 * All rights reserved.
7 * Copyright (c) 2023 Jessica Clarke <jrtc27@FreeBSD.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #ifndef _SYS_LINKER_SET_H_
32 #define _SYS_LINKER_SET_H_
33
34 #include <mach-o/dyld.h>
35 #include <mach-o/getsect.h>
36
37 /*
38 * The following macros are used to declare global sets of objects, which
39 * are collected by the linker into a `linker_set' as defined below.
40 * For Mach-O, this is done by constructing a separate section for each set.
41 */
42
43 #define __MAKE_SET_CONST const
44
45 /*
46 * Private macros, not to be used outside this header file.
47 */
48
49 /*
50 * The userspace address sanitizer inserts redzones around global variables,
51 * violating the assumption that linker set elements are packed.
52 */
53 #define __NOASAN __nosanitizeaddress
54
55 #define __MAKE_SET_QV(set, sym, qv) \
56 static void const * qv \
57 __NOASAN \
58 __set_##set##_sym_##sym __section("__DATA,set_" #set) \
59 __used = &(sym)
60 #define __MAKE_SET(set, sym) __MAKE_SET_QV(set, sym, __MAKE_SET_CONST)
61
62 static inline __pure2 uint8_t *
__set_getsectiondata(const char * segname,const char * sectname,unsigned long * size)63 __set_getsectiondata(const char *segname, const char *sectname,
64 unsigned long *size)
65 {
66 uint32_t image_count, image_index;
67 const struct mach_header *mh;
68 uint8_t *ret;
69
70 image_count = _dyld_image_count();
71 for (image_index = 0; image_index < image_count; ++image_index) {
72 mh = _dyld_get_image_header(image_index);
73 if (mh == NULL)
74 continue;
75
76 ret = getsectiondata((const struct mach_header_64 *)mh,
77 segname, sectname, size);
78 if (ret != NULL)
79 return (ret);
80 }
81
82 return (NULL);
83 }
84
85 #define __SET_RANGE(set) ({ \
86 unsigned long __set_size; \
87 char *__set_data; \
88 __set_data = __set_getsectiondata("__DATA", \
89 "set_" #set, &__set_size); \
90 (struct { \
91 __CONCAT(__typeof_set_,set) **begin; \
92 __CONCAT(__typeof_set_,set) **limit; \
93 }){ \
94 .begin = (__CONCAT(__typeof_set_,set) **)__set_data, \
95 .limit = (__CONCAT(__typeof_set_,set) **)(__set_data + \
96 __set_size) \
97 }; \
98 })
99
100 /*
101 * Public macros.
102 */
103 #define TEXT_SET(set, sym) __MAKE_SET(set, sym)
104 #define DATA_SET(set, sym) __MAKE_SET(set, sym)
105 #define DATA_WSET(set, sym) __MAKE_SET_QV(set, sym, )
106 #define BSS_SET(set, sym) __MAKE_SET(set, sym)
107 #define ABS_SET(set, sym) __MAKE_SET(set, sym)
108 #define SET_ENTRY(set, sym) __MAKE_SET(set, sym)
109
110 /*
111 * Initialize before referring to a given linker set.
112 */
113 #define SET_DECLARE(set, ptype) \
114 typedef ptype __CONCAT(__typeof_set_,set)
115
116 #define SET_BEGIN(set) \
117 (__SET_RANGE(set).begin)
118 #define SET_LIMIT(set) \
119 (__SET_RANGE(set).limit)
120
121 /*
122 * Iterate over all the elements of a set.
123 *
124 * Sets always contain addresses of things, and "pvar" points to words
125 * containing those addresses. Thus is must be declared as "type **pvar",
126 * and the address of each set item is obtained inside the loop by "*pvar".
127 */
128 #define SET_FOREACH(pvar, set) \
129 for (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++)
130
131 #define SET_ITEM(set, i) \
132 ((SET_BEGIN(set))[i])
133
134 /*
135 * Provide a count of the items in a set.
136 */
137 #define SET_COUNT(set) \
138 (SET_LIMIT(set) - SET_BEGIN(set))
139
140 #endif /* _SYS_LINKER_SET_H_ */
141