[tables] Redefine methods for accessing linker tables
[people/lynusvaz/gpxe.git] / src / include / gpxe / tables.h
1 #ifndef _GPXE_TABLES_H
2 #define _GPXE_TABLES_H
3
4 /** @page ifdef_harmful #ifdef considered harmful
5  *
6  * Overuse of @c #ifdef has long been a problem in Etherboot.
7  * Etherboot provides a rich array of features, but all these features
8  * take up valuable space in a ROM image.  The traditional solution to
9  * this problem has been for each feature to have its own @c #ifdef
10  * option, allowing the feature to be compiled in only if desired.
11  *
12  * The problem with this is that it becomes impossible to compile, let
13  * alone test, all possible versions of Etherboot.  Code that is not
14  * typically used tends to suffer from bit-rot over time.  It becomes
15  * extremely difficult to predict which combinations of compile-time
16  * options will result in code that can even compile and link
17  * correctly.
18  *
19  * To solve this problem, we have adopted a new approach from
20  * Etherboot 5.5 onwards.  @c #ifdef is now "considered harmful", and
21  * its use should be minimised.  Separate features should be
22  * implemented in separate @c .c files, and should \b always be
23  * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
24  * MY_PET_FEATURE statement).  By making (almost) all code always
25  * compile, we avoid the problem of bit-rot in rarely-used code.
26  *
27  * The file config.h, in combination with the @c make command line,
28  * specifies the objects that will be included in any particular build
29  * of Etherboot.  For example, suppose that config.h includes the line
30  *
31  * @code
32  *
33  *   #define CONSOLE_SERIAL
34  *   #define DOWNLOAD_PROTO_TFTP
35  *
36  * @endcode
37  *
38  * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
39  * built, the options specified in config.h are used to drag in the
40  * relevant objects at link-time.  For the above example, serial.o and
41  * tftp.o would be linked in.
42  *
43  * There remains one problem to solve: how do these objects get used?
44  * Traditionally, we had code such as
45  *
46  * @code
47  *
48  *    #ifdef CONSOLE_SERIAL
49  *      serial_init();
50  *    #endif
51  *
52  * @endcode
53  *
54  * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
55  * We cannot simply remove the @c #ifdef and make it
56  *
57  * @code
58  *
59  *   serial_init();
60  *
61  * @endcode
62  *
63  * because then serial.o would end up always being linked in.
64  *
65  * The solution is to use @link tables.h linker tables @endlink.
66  *
67  */
68
69 /** @file
70  *
71  * Linker tables
72  *
73  * Read @ref ifdef_harmful first for some background on the motivation
74  * for using linker tables.
75  *
76  * This file provides macros for dealing with linker-generated tables
77  * of fixed-size symbols.  We make fairly extensive use of these in
78  * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
79  * For example, instead of having code such as
80  *
81  * @code
82  *
83  *    #ifdef CONSOLE_SERIAL
84  *      serial_init();
85  *    #endif
86  *
87  * @endcode
88  *
89  * we make serial.c generate an entry in the initialisation function
90  * table, and then have a function call_init_fns() that simply calls
91  * all functions present in this table.  If and only if serial.o gets
92  * linked in, then its initialisation function will be called.  We
93  * avoid linker symbol pollution (i.e. always dragging in serial.o
94  * just because of a call to serial_init()) and we also avoid @c
95  * #ifdef spaghetti (having to conditionalise every reference to
96  * functions in serial.c).
97  *
98  * The linker script takes care of assembling the tables for us.  All
99  * our table sections have names of the format @c .tbl.NAME.NN where
100  * @c NAME designates the data structure stored in the table (e.g. @c
101  * init_fn) and @c NN is a two-digit decimal number used to impose an
102  * ordering upon the tables if required.  @c NN=00 is reserved for the
103  * symbol indicating "table start", and @c NN=99 is reserved for the
104  * symbol indicating "table end".
105  *
106  * As an example, suppose that we want to create a "frobnicator"
107  * feature framework, and allow for several independent modules to
108  * provide frobnicating services.  Then we would create a frob.h
109  * header file containing e.g.
110  *
111  * @code
112  *
113  *   struct frobnicator {
114  *      const char *name;               // Name of the frobnicator
115  *      void ( *frob ) ( void );        // The frobnicating function itself
116  *   };
117  *
118  *   #define __frobnicator __table ( struct frobnicator, "frobnicators", 01 )
119  *
120  * @endcode
121  *
122  * Any module providing frobnicating services would look something
123  * like
124  *
125  * @code
126  *
127  *   #include "frob.h"
128  *
129  *   static void my_frob ( void ) {
130  *      // Do my frobnicating
131  *      ...
132  *   }
133  *
134  *   struct frob my_frobnicator __frobnicator = {
135  *      .name = "my_frob",
136  *      .frob = my_frob,
137  *   };
138  *
139  * @endcode
140  *
141  * The central frobnicator code (frob.c) would use the frobnicating
142  * modules as follows
143  *
144  * @code
145  *
146  *   #include "frob.h"
147  *
148  *   // Call all linked-in frobnicators
149  *   void frob_all ( void ) {
150  *      struct frob *frob;
151  *
152  *      for_each_table ( frob, "frobnicators" ) {
153  *         printf ( "Calling frobnicator \"%s\"\n", frob->name );
154  *         frob->frob ();
155  *      }
156  *   }
157  *
158  * @endcode
159  *
160  * See init.h and init.c for a real-life example.
161  *
162  */
163
164 #ifdef DOXYGEN
165 #define __attribute__( x )
166 #endif
167
168 #define __table_str( x ) #x
169 #define __table_section( table, idx ) \
170         __section__ ( ".tbl." table "." __table_str ( idx ) )
171
172 #define __table_section_start( table ) __table_section ( table, 00 )
173 #define __table_section_end( table ) __table_section ( table, 99 )
174
175 #define __natural_alignment( type ) __aligned__ ( __alignof__ ( type ) )
176
177 /**
178  * Linker table entry.
179  *
180  * Declares a data structure to be part of a linker table.  Use as
181  * e.g.
182  *
183  * @code
184  *
185  *   #define __frobnicator __table ( struct frobnicator, "frobnicators", 01 )
186  *
187  *   struct frobnicator my_frob __frobnicator = {
188  *      ...
189  *   };
190  *
191  * @endcode
192  *
193  */
194 #define __table( type, table, idx )                                     \
195         __attribute__ (( __table_section ( table, idx ),                \
196                          __natural_alignment ( type ) ))
197
198 /**
199  * Start of linker table.
200  *
201  * Return the start of a linker table.  Use as e.g.
202  *
203  * @code
204  *
205  *   struct frobnicator *frobs =
206  *      table_start ( struct frobnicator, "frobnicators" );
207  *
208  * @endcode
209  *
210  */
211 #define table_start( type, table ) ( {                                  \
212         static type __table_start[0] __table ( type, table, 00 );       \
213         __table_start; } )
214
215 /**
216  * End of linker table.
217  *
218  * Return the end of a linker table.  Use as e.g.
219  *
220  * @code
221  *
222  *   struct frobnicator *frobs_end =
223  *      table_end ( struct frobnicator, "frobnicators" );
224  *
225  * @endcode
226  *
227  */
228 #define table_end( type, table ) ( {                                    \
229         static type __table_end[0] __table ( type, table, 99 );         \
230         __table_end; } )
231
232 /**
233  * Calculate number of entries in linker table.
234  *
235  * Return the number of entries within a linker table.  Use as e.g.
236  *
237  * @code
238  *
239  *   unsigned int num_frobs =
240  *      table_num_entries ( struct frobnicator, "frobnicators" );
241  *
242  * @endcode
243  *
244  */
245 #define table_num_entries( type, table )                                \
246         ( ( unsigned int ) ( table_end ( type, table ) -                \
247                              table_start ( type, table ) ) )
248
249 /**
250  * Iterate through all entries within a linker table.
251  *
252  * Use as e.g.
253  *
254  * @code
255  *
256  *   struct frobnicator *frob;
257  *
258  *   for_each_table_entry ( frob, "frobnicators" ) {
259  *     ...
260  *   }
261  *
262  * @endcode
263  *
264  */
265 #define for_each_table_entry( pointer, table )                          \
266         for ( pointer = table_start ( typeof ( * pointer ), table ) ;   \
267               pointer < table_end ( typeof ( * pointer ), table ) ;     \
268               pointer++ )
269
270 /**
271  * Iterate through all entries within a linker table in reverse order.
272  *
273  * Use as e.g.
274  *
275  * @code
276  *
277  *   struct frobnicator *frob;
278  *
279  *   for_each_table_entry_reverse ( frob, "frobnicators" ) {
280  *     ...
281  *   }
282  *
283  * @endcode
284  *
285  */
286 #define for_each_table_entry_reverse( pointer, table )                  \
287         for ( pointer = table_end ( typeof ( * pointer ), table ) - 1 ; \
288               pointer >= table_start ( typeof ( * pointer ), table ) ;  \
289               pointer-- )
290
291 #endif /* _GPXE_TABLES_H */