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 *
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