4 FILE_LICENCE ( GPL2_OR_LATER );
6 /** @page ifdef_harmful #ifdef considered harmful
8 * Overuse of @c #ifdef has long been a problem in Etherboot.
9 * Etherboot provides a rich array of features, but all these features
10 * take up valuable space in a ROM image. The traditional solution to
11 * this problem has been for each feature to have its own @c #ifdef
12 * option, allowing the feature to be compiled in only if desired.
14 * The problem with this is that it becomes impossible to compile, let
15 * alone test, all possible versions of Etherboot. Code that is not
16 * typically used tends to suffer from bit-rot over time. It becomes
17 * extremely difficult to predict which combinations of compile-time
18 * options will result in code that can even compile and link
21 * To solve this problem, we have adopted a new approach from
22 * Etherboot 5.5 onwards. @c #ifdef is now "considered harmful", and
23 * its use should be minimised. Separate features should be
24 * implemented in separate @c .c files, and should \b always be
25 * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
26 * MY_PET_FEATURE statement). By making (almost) all code always
27 * compile, we avoid the problem of bit-rot in rarely-used code.
29 * The file config.h, in combination with the @c make command line,
30 * specifies the objects that will be included in any particular build
31 * of Etherboot. For example, suppose that config.h includes the line
35 * #define CONSOLE_SERIAL
36 * #define DOWNLOAD_PROTO_TFTP
40 * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
41 * built, the options specified in config.h are used to drag in the
42 * relevant objects at link-time. For the above example, serial.o and
43 * tftp.o would be linked in.
45 * There remains one problem to solve: how do these objects get used?
46 * Traditionally, we had code such as
50 * #ifdef CONSOLE_SERIAL
56 * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
57 * We cannot simply remove the @c #ifdef and make it
65 * because then serial.o would end up always being linked in.
67 * The solution is to use @link tables.h linker tables @endlink.
75 * Read @ref ifdef_harmful first for some background on the motivation
76 * for using linker tables.
78 * This file provides macros for dealing with linker-generated tables
79 * of fixed-size symbols. We make fairly extensive use of these in
80 * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
81 * For example, instead of having code such as
85 * #ifdef CONSOLE_SERIAL
91 * we make serial.c generate an entry in the initialisation function
92 * table, and then have a function call_init_fns() that simply calls
93 * all functions present in this table. If and only if serial.o gets
94 * linked in, then its initialisation function will be called. We
95 * avoid linker symbol pollution (i.e. always dragging in serial.o
96 * just because of a call to serial_init()) and we also avoid @c
97 * #ifdef spaghetti (having to conditionalise every reference to
98 * functions in serial.c).
100 * The linker script takes care of assembling the tables for us. All
101 * our table sections have names of the format @c .tbl.NAME.NN where
102 * @c NAME designates the data structure stored in the table (e.g. @c
103 * init_fns) and @c NN is a two-digit decimal number used to impose an
104 * ordering upon the tables if required. @c NN=00 is reserved for the
105 * symbol indicating "table start", and @c NN=99 is reserved for the
106 * symbol indicating "table end".
108 * As an example, suppose that we want to create a "frobnicator"
109 * feature framework, and allow for several independent modules to
110 * provide frobnicating services. Then we would create a frob.h
111 * header file containing e.g.
115 * struct frobnicator {
116 * const char *name; // Name of the frobnicator
117 * void ( *frob ) ( void ); // The frobnicating function itself
120 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
122 * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
126 * Any module providing frobnicating services would look something
133 * static void my_frob ( void ) {
134 * // Do my frobnicating
138 * struct frob my_frobnicator __frobnicator = {
145 * The central frobnicator code (frob.c) would use the frobnicating
152 * // Call all linked-in frobnicators
153 * void frob_all ( void ) {
156 * for_each_table ( frob, FROBNICATORS ) {
157 * printf ( "Calling frobnicator \"%s\"\n", frob->name );
164 * See init.h and init.c for a real-life example.
169 #define __attribute__( x )
173 * Declare a linker table
177 * @ret table Linker table
179 #define __table( type, name ) ( type, name )
182 * Get linker table data type
184 * @v table Linker table
185 * @ret type Data type
187 #define __table_type( table ) __table_extract_type table
188 #define __table_extract_type( type, name ) type
191 * Get linker table name
193 * @v table Linker table
194 * @ret name Table name
196 #define __table_name( table ) __table_extract_name table
197 #define __table_extract_name( type, name ) name
200 * Get linker table section name
202 * @v table Linker table
203 * @v idx Sub-table index
204 * @ret section Section name
206 #define __table_section( table, idx ) \
207 ".tbl." __table_name ( table ) "." __table_str ( idx )
208 #define __table_str( x ) #x
211 * Get linker table alignment
213 * @v table Linker table
214 * @ret align Alignment
216 #define __table_alignment( table ) __alignof__ ( __table_type ( table ) )
219 * Declare a linker table entry
221 * @v table Linker table
222 * @v idx Sub-table index
228 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
230 * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
232 * struct frobnicator my_frob __frobnicator = {
238 #define __table_entry( table, idx ) \
239 __attribute__ (( __section__ ( __table_section ( table, idx ) ),\
240 __aligned__ ( __table_alignment ( table ) ) ))
243 * Get start of linker table entries
245 * @v table Linker table
246 * @v idx Sub-table index
247 * @ret entries Start of entries
249 #define __table_entries( table, idx ) ( { \
250 static __table_type ( table ) __table_entries[0] \
251 __table_entry ( table, idx ) \
252 __attribute__ (( unused )); \
256 * Get start of linker table
258 * @v table Linker table
259 * @ret start Start of linker table
265 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
267 * struct frobnicator *frobs = table_start ( FROBNICATORS );
271 #define table_start( table ) __table_entries ( table, 00 )
274 * Get end of linker table
276 * @v table Linker table
277 * @ret end End of linker table
283 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
285 * struct frobnicator *frobs_end = table_end ( FROBNICATORS );
289 #define table_end( table ) __table_entries ( table, 99 )
292 * Get number of entries in linker table
294 * @v table Linker table
295 * @ret num_entries Number of entries in linker table
301 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
303 * unsigned int num_frobs = table_num_entries ( FROBNICATORS );
308 #define table_num_entries( table ) \
309 ( ( unsigned int ) ( table_end ( table ) - \
310 table_start ( table ) ) )
313 * Get index of entry within linker table
315 * @v table Linker table
316 * @v entry Table entry
322 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
324 * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
326 * struct frobnicator my_frob __frobnicator = {
330 * unsigned int my_frob_idx = table_index ( FROBNICATORS, &my_frob );
334 #define table_index( table, entry ) \
335 ( ( unsigned int ) ( (entry) - table_start ( table ) ) )
338 * Iterate through all entries within a linker table
340 * @v pointer Entry pointer
341 * @v table Linker table
347 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
349 * struct frobnicator *frob;
351 * for_each_table_entry ( frob, FROBNICATORS ) {
358 #define for_each_table_entry( pointer, table ) \
359 for ( pointer = table_start ( table ) ; \
360 pointer < table_end ( table ) ; \
364 * Iterate through all remaining entries within a linker table
366 * @v pointer Entry pointer, preset to most recent entry
367 * @v table Linker table
373 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
374 * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
376 * struct frob my_frobnicator __frobnicator;
377 * struct frobnicator *frob;
379 * frob = &my_frobnicator;
380 * for_each_table_entry_continue ( frob, FROBNICATORS ) {
387 #define for_each_table_entry_continue( pointer, table ) \
389 pointer < table_end ( table ) ; \
393 * Iterate through all entries within a linker table in reverse order
395 * @v pointer Entry pointer
396 * @v table Linker table
402 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
404 * struct frobnicator *frob;
406 * for_each_table_entry_reverse ( frob, FROBNICATORS ) {
413 #define for_each_table_entry_reverse( pointer, table ) \
414 for ( pointer = ( table_end ( table ) - 1 ) ; \
415 pointer >= table_start ( table ) ; \
419 * Iterate through all remaining entries within a linker table in reverse order
421 * @v pointer Entry pointer, preset to most recent entry
422 * @v table Linker table
428 * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
429 * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
431 * struct frob my_frobnicator __frobnicator;
432 * struct frobnicator *frob;
434 * frob = &my_frobnicator;
435 * for_each_table_entry_continue_reverse ( frob, FROBNICATORS ) {
442 #define for_each_table_entry_continue_reverse( pointer, table ) \
444 pointer >= table_start ( table ) ; \
447 /******************************************************************************
449 * Intel's C compiler chokes on several of the constructs used in this
450 * file. The workarounds are ugly, so we use them only for an icc
454 #define ICC_ALIGN_HACK_FACTOR 128
458 * icc miscompiles zero-length arrays by inserting padding to a length
459 * of two array elements. We therefore have to generate the
460 * __table_entries() symbols by hand in asm.
463 #undef __table_entries
464 #define __table_entries( table, idx ) ( { \
465 extern __table_type ( table ) \
466 __table_temp_sym ( idx, __LINE__ ) [] \
467 __table_entry ( table, idx ) \
468 asm ( __table_entries_sym ( table, idx ) ); \
469 __asm__ ( ".ifndef %c0\n\t" \
470 ".section " __table_section ( table, idx ) "\n\t" \
475 : : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \
476 "i" ( __table_alignment ( table ) ) ); \
477 __table_temp_sym ( idx, __LINE__ ); } )
478 #define __table_entries_sym( table, idx ) \
479 "__tbl_" __table_name ( table ) "_" #idx
480 #define __table_temp_sym( a, b ) \
481 ___table_temp_sym( __table_, a, _, b )
482 #define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d
485 * icc ignores __attribute__ (( aligned (x) )) when it is used to
486 * decrease the compiler's default choice of alignment (which may be
487 * higher than the alignment actually required by the structure). We
488 * work around this by forcing the alignment to a large multiple of
489 * the required value (so that we are never attempting to decrease the
490 * default alignment) and then postprocessing the object file to
491 * reduce the alignment back down to the "real" value.
494 #undef __table_alignment
495 #define __table_alignment( table ) \
496 ( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) )
499 * Because of the alignment hack, we must ensure that the compiler
500 * never tries to place multiple objects within the same section,
501 * otherwise the assembler will insert padding to the (incorrect)
502 * alignment boundary. Do this by appending the line number to table
505 * Note that we don't need to worry about padding between array
506 * elements, since the alignment is declared on the variable (i.e. the
507 * whole array) rather than on the type (i.e. on all individual array
510 #undef __table_section
511 #define __table_section( table, idx ) \
512 ".tbl." __table_name ( table ) "." __table_str ( idx ) \
513 "." __table_xstr ( __LINE__ )
514 #define __table_xstr( x ) __table_str ( x )
518 #endif /* _IPXE_TABLES_H */