aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/include/gpxe/tables.h
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/include/gpxe/tables.h')
-rw-r--r--gpxe/src/include/gpxe/tables.h263
1 files changed, 234 insertions, 29 deletions
diff --git a/gpxe/src/include/gpxe/tables.h b/gpxe/src/include/gpxe/tables.h
index b2c56ab6..7dfced8c 100644
--- a/gpxe/src/include/gpxe/tables.h
+++ b/gpxe/src/include/gpxe/tables.h
@@ -1,6 +1,8 @@
#ifndef _GPXE_TABLES_H
#define _GPXE_TABLES_H
+FILE_LICENCE ( GPL2_OR_LATER );
+
/** @page ifdef_harmful #ifdef considered harmful
*
* Overuse of @c #ifdef has long been a problem in Etherboot.
@@ -98,7 +100,7 @@
* The linker script takes care of assembling the tables for us. All
* our table sections have names of the format @c .tbl.NAME.NN where
* @c NAME designates the data structure stored in the table (e.g. @c
- * init_fn) and @c NN is a two-digit decimal number used to impose an
+ * init_fns) and @c NN is a two-digit decimal number used to impose an
* ordering upon the tables if required. @c NN=00 is reserved for the
* symbol indicating "table start", and @c NN=99 is reserved for the
* symbol indicating "table end".
@@ -115,7 +117,9 @@
* void ( *frob ) ( void ); // The frobnicating function itself
* };
*
- * #define __frobnicator __table ( frobnicators, 01 )
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
*
* @endcode
*
@@ -145,14 +149,11 @@
*
* #include "frob.h"
*
- * static struct frob frob_start[0] __table_start ( frobnicators );
- * static struct frob frob_end[0] __table_end ( frobnicators );
- *
* // Call all linked-in frobnicators
* void frob_all ( void ) {
* struct frob *frob;
*
- * for ( frob = frob_start ; frob < frob_end ; frob++ ) {
+ * for_each_table ( frob, FROBNICATORS ) {
* printf ( "Calling frobnicator \"%s\"\n", frob->name );
* frob->frob ();
* }
@@ -168,62 +169,266 @@
#define __attribute__( x )
#endif
-#define __table_str( x ) #x
-#define __table_section( table, idx ) \
- __section__ ( ".tbl." __table_str ( table ) "." __table_str ( idx ) )
+/**
+ * Declare a linker table
+ *
+ * @v type Data type
+ * @v name Table name
+ * @ret table Linker table
+ */
+#define __table( type, name ) ( type, name )
-#define __table_section_start( table ) __table_section ( table, 00 )
-#define __table_section_end( table ) __table_section ( table, 99 )
+/**
+ * Get linker table data type
+ *
+ * @v table Linker table
+ * @ret type Data type
+ */
+#define __table_type( table ) __table_extract_type table
+#define __table_extract_type( type, name ) type
-#define __natural_alignment( type ) __aligned__ ( __alignof__ ( type ) )
+/**
+ * Get linker table name
+ *
+ * @v table Linker table
+ * @ret name Table name
+ */
+#define __table_name( table ) __table_extract_name table
+#define __table_extract_name( type, name ) name
/**
- * Linker table entry.
+ * Get linker table section name
*
- * Declares a data structure to be part of a linker table. Use as
- * e.g.
+ * @v table Linker table
+ * @v idx Sub-table index
+ * @ret section Section name
+ */
+#define __table_section( table, idx ) \
+ ".tbl." __table_name ( table ) "." __table_str ( idx )
+#define __table_str( x ) #x
+
+/**
+ * Get linker table alignment
+ *
+ * @v table Linker table
+ * @ret align Alignment
+ */
+#define __table_alignment( table ) __alignof__ ( __table_type ( table ) )
+
+/**
+ * Declare a linker table entry
+ *
+ * @v table Linker table
+ * @v idx Sub-table index
+ *
+ * Example usage:
*
* @code
*
- * struct my_foo __table ( foo, 01 ) = {
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * #define __frobnicator __table_entry ( FROBNICATORS, 01 )
+ *
+ * struct frobnicator my_frob __frobnicator = {
* ...
* };
*
* @endcode
+ */
+#define __table_entry( table, idx ) \
+ __attribute__ (( __section__ ( __table_section ( table, idx ) ),\
+ __aligned__ ( __table_alignment ( table ) ) ))
+
+/**
+ * Get start of linker table entries
+ *
+ * @v table Linker table
+ * @v idx Sub-table index
+ * @ret entries Start of entries
+ */
+#define __table_entries( table, idx ) ( { \
+ static __table_type ( table ) __table_entries[0] \
+ __table_entry ( table, idx ); \
+ __table_entries; } )
+
+/**
+ * Get start of linker table
+ *
+ * @v table Linker table
+ * @ret start Start of linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * struct frobnicator *frobs = table_start ( FROBNICATORS );
+ *
+ * @endcode
+ */
+#define table_start( table ) __table_entries ( table, 00 )
+
+/**
+ * Get end of linker table
+ *
+ * @v table Linker table
+ * @ret end End of linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * struct frobnicator *frobs_end = table_end ( FROBNICATORS );
+ *
+ * @endcode
+ */
+#define table_end( table ) __table_entries ( table, 99 )
+
+/**
+ * Get number of entries in linker table
+ *
+ * @v table Linker table
+ * @ret num_entries Number of entries in linker table
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * unsigned int num_frobs = table_num_entries ( FROBNICATORS );
+ *
+ * @endcode
*
*/
-#define __table( type, table, idx ) \
- __attribute__ (( __table_section ( table, idx ), \
- __natural_alignment ( type ) ))
+#define table_num_entries( table ) \
+ ( ( unsigned int ) ( table_end ( table ) - \
+ table_start ( table ) ) )
/**
- * Linker table start marker.
+ * Iterate through all entries within a linker table
+ *
+ * @v pointer Entry pointer
+ * @v table Linker table
*
- * Declares a data structure (usually an empty data structure) to be
- * the start of a linker table. Use as e.g.
+ * Example usage:
*
* @code
*
- * static struct foo_start[0] __table_start ( foo );
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * struct frobnicator *frob;
+ *
+ * for_each_table_entry ( frob, FROBNICATORS ) {
+ * ...
+ * }
*
* @endcode
*
*/
-#define __table_start( type, table ) __table ( type, table, 00 )
+#define for_each_table_entry( pointer, table ) \
+ for ( pointer = table_start ( table ) ; \
+ pointer < table_end ( table ) ; \
+ pointer++ )
/**
- * Linker table end marker.
+ * Iterate through all entries within a linker table in reverse order
*
- * Declares a data structure (usually an empty data structure) to be
- * the end of a linker table. Use as e.g.
+ * @v pointer Entry pointer
+ * @v table Linker table
+ *
+ * Example usage:
*
* @code
*
- * static struct foo_end[0] __table_end ( foo );
+ * #define FROBNICATORS __table ( struct frobnicator, "frobnicators" )
+ *
+ * struct frobnicator *frob;
+ *
+ * for_each_table_entry_reverse ( frob, FROBNICATORS ) {
+ * ...
+ * }
*
* @endcode
*
*/
-#define __table_end( type, table ) __table ( type, table, 99 )
+#define for_each_table_entry_reverse( pointer, table ) \
+ for ( pointer = ( table_end ( table ) - 1 ) ; \
+ pointer >= table_start ( table ) ; \
+ pointer-- )
+
+/******************************************************************************
+ *
+ * Intel's C compiler chokes on several of the constructs used in this
+ * file. The workarounds are ugly, so we use them only for an icc
+ * build.
+ *
+ */
+#define ICC_ALIGN_HACK_FACTOR 128
+#ifdef __ICC
+
+/*
+ * icc miscompiles zero-length arrays by inserting padding to a length
+ * of two array elements. We therefore have to generate the
+ * __table_entries() symbols by hand in asm.
+ *
+ */
+#undef __table_entries
+#define __table_entries( table, idx ) ( { \
+ extern __table_type ( table ) \
+ __table_temp_sym ( idx, __LINE__ ) [] \
+ __table_entry ( table, idx ) \
+ asm ( __table_entries_sym ( table, idx ) ); \
+ __asm__ ( ".ifndef %c0\n\t" \
+ ".section " __table_section ( table, idx ) "\n\t" \
+ ".align %c1\n\t" \
+ "\n%c0:\n\t" \
+ ".previous\n\t" \
+ ".endif\n\t" \
+ : : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \
+ "i" ( __table_alignment ( table ) ) ); \
+ __table_temp_sym ( idx, __LINE__ ); } )
+#define __table_entries_sym( table, idx ) \
+ "__tbl_" __table_name ( table ) "_" #idx
+#define __table_temp_sym( a, b ) \
+ ___table_temp_sym( __table_, a, _, b )
+#define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d
+
+/*
+ * icc ignores __attribute__ (( aligned (x) )) when it is used to
+ * decrease the compiler's default choice of alignment (which may be
+ * higher than the alignment actually required by the structure). We
+ * work around this by forcing the alignment to a large multiple of
+ * the required value (so that we are never attempting to decrease the
+ * default alignment) and then postprocessing the object file to
+ * reduce the alignment back down to the "real" value.
+ *
+ */
+#undef __table_alignment
+#define __table_alignment( table ) \
+ ( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) )
+
+/*
+ * Because of the alignment hack, we must ensure that the compiler
+ * never tries to place multiple objects within the same section,
+ * otherwise the assembler will insert padding to the (incorrect)
+ * alignment boundary. Do this by appending the line number to table
+ * section names.
+ *
+ * Note that we don't need to worry about padding between array
+ * elements, since the alignment is declared on the variable (i.e. the
+ * whole array) rather than on the type (i.e. on all individual array
+ * elements).
+ */
+#undef __table_section
+#define __table_section( table, idx ) \
+ ".tbl." __table_name ( table ) "." __table_str ( idx ) \
+ "." __table_xstr ( __LINE__ )
+#define __table_xstr( x ) __table_str ( x )
+
+#endif /* __ICC */
#endif /* _GPXE_TABLES_H */