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
62static 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