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