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 ); \
255
* Get start of linker table
257
* @v table Linker table
258
* @ret start Start of linker table
264
* #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
266
* struct frobnicator *frobs = table_start ( FROBNICATORS );
270
#define table_start( table ) __table_entries ( table, 00 )
273
* Get end of linker table
275
* @v table Linker table
276
* @ret end End of linker table
282
* #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
284
* struct frobnicator *frobs_end = table_end ( FROBNICATORS );
288
#define table_end( table ) __table_entries ( table, 99 )
291
* Get number of entries in linker table
293
* @v table Linker table
294
* @ret num_entries Number of entries in linker table
300
* #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
302
* unsigned int num_frobs = table_num_entries ( FROBNICATORS );
307
#define table_num_entries( table ) \
308
( ( unsigned int ) ( table_end ( table ) - \
309
table_start ( table ) ) )
312
* Iterate through all entries within a linker table
314
* @v pointer Entry pointer
315
* @v table Linker table
321
* #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
323
* struct frobnicator *frob;
325
* for_each_table_entry ( frob, FROBNICATORS ) {
332
#define for_each_table_entry( pointer, table ) \
333
for ( pointer = table_start ( table ) ; \
334
pointer < table_end ( table ) ; \
338
* Iterate through all entries within a linker table in reverse order
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_reverse ( frob, FROBNICATORS ) {
358
#define for_each_table_entry_reverse( pointer, table ) \
359
for ( pointer = ( table_end ( table ) - 1 ) ; \
360
pointer >= table_start ( table ) ; \
363
/******************************************************************************
365
* Intel's C compiler chokes on several of the constructs used in this
366
* file. The workarounds are ugly, so we use them only for an icc
370
#define ICC_ALIGN_HACK_FACTOR 128
374
* icc miscompiles zero-length arrays by inserting padding to a length
375
* of two array elements. We therefore have to generate the
376
* __table_entries() symbols by hand in asm.
379
#undef __table_entries
380
#define __table_entries( table, idx ) ( { \
381
extern __table_type ( table ) \
382
__table_temp_sym ( idx, __LINE__ ) [] \
383
__table_entry ( table, idx ) \
384
asm ( __table_entries_sym ( table, idx ) ); \
385
__asm__ ( ".ifndef %c0\n\t" \
386
".section " __table_section ( table, idx ) "\n\t" \
391
: : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \
392
"i" ( __table_alignment ( table ) ) ); \
393
__table_temp_sym ( idx, __LINE__ ); } )
394
#define __table_entries_sym( table, idx ) \
395
"__tbl_" __table_name ( table ) "_" #idx
396
#define __table_temp_sym( a, b ) \
397
___table_temp_sym( __table_, a, _, b )
398
#define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d
401
* icc ignores __attribute__ (( aligned (x) )) when it is used to
402
* decrease the compiler's default choice of alignment (which may be
403
* higher than the alignment actually required by the structure). We
404
* work around this by forcing the alignment to a large multiple of
405
* the required value (so that we are never attempting to decrease the
406
* default alignment) and then postprocessing the object file to
407
* reduce the alignment back down to the "real" value.
410
#undef __table_alignment
411
#define __table_alignment( table ) \
412
( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) )
415
* Because of the alignment hack, we must ensure that the compiler
416
* never tries to place multiple objects within the same section,
417
* otherwise the assembler will insert padding to the (incorrect)
418
* alignment boundary. Do this by appending the line number to table
421
* Note that we don't need to worry about padding between array
422
* elements, since the alignment is declared on the variable (i.e. the
423
* whole array) rather than on the type (i.e. on all individual array
426
#undef __table_section
427
#define __table_section( table, idx ) \
428
".tbl." __table_name ( table ) "." __table_str ( idx ) \
429
"." __table_xstr ( __LINE__ )
430
#define __table_xstr( x ) __table_str ( x )
434
#endif /* _GPXE_TABLES_H */