1

I'm looking over the iPXE source code to try to understand what happens early on at this stage of boot up, but there is some major nested macro expansion going on that I'm unfamiliar with and having trouble following.

In one of the source files (core/init.c), there is:

void initialise ( void ) {
    struct init_fn *init_fn;

    /* Call registered initialisation functions */
    for_each_table_entry ( init_fn, INIT_FNS )
            init_fn->initialise ();
}

So I'm walking through the expansion of for_each_table_entry.

Here are some of the relevant macro definitions:

#define for_each_table_entry( pointer, table )                          \
    for ( pointer = table_start ( table ) ;                         \
          pointer < table_end ( table ) ;                           \
          pointer++ )

#define table_start( table ) __table_entries ( table, 00 )

#define table_end( table ) __table_entries ( table, 99 )

#define __table_entries( table, idx ) ( {                               \
    static __table_type ( table ) __table_entries[0]                \
            __table_entry ( table, idx )                            \
            __attribute__ (( unused ));                             \
    __table_entries; } )

#define __table_type( table ) __table_extract_type table
#define __table_extract_type( type, name ) type

#define __table_entry( table, idx )                                     \
    __attribute__ (( __section__ ( __table_section ( table, idx ) ),\
                     __aligned__ ( __table_alignment ( table ) ) ))

#define __table_section( table, idx ) \
    ".tbl." __table_name ( table ) "." __table_str ( idx )
#define __table_str( x ) #x

#define __table_alignment( table ) __alignof__ ( __table_type ( table ) )

#define __table_name( table ) __table_extract_name table
#define __table_extract_name( type, name ) name

Phew, I think that may be it. A ridiculous amount of nested expansion in my opinion.

So if I try to manually expand to see what is going on, I get:

# 1
for_each_table_entry ( init_fn, INIT_FNS )

# 2
for ( init_fn = table_start ( INIT_FNS ) ;                               \
      init_fn < table_end ( INIT_FNS ) ;                                 \
      init_fn++ )

# 3
for ( init_fn = __table_entries ( INIT_FNS, 00 ) ;                       \
      init_fn < __table_entries ( INIT_FNS, 00 ) ;                       \
      init_fn++ )

# 4
for ( init_fn = ( {                                                      \
    static __table_type ( INIT_FNS ) __table_entries[0]                  \
            __table_entry ( INIT_FNS, 00 )                               \
            __attribute__ (( unused ));                                  \
    __table_entries; } ) ;                                               \
      init_fn < ( {                                                      \
    static __table_type ( INIT_FNS ) __table_entries[0]                  \
            __table_entry ( INIT_FNS, 99 )                               \
            __attribute__ (( unused ));                                  \
    __table_entries; } ) ;                                               \
      init_fn++ )

# 5
for ( init_fn = ( {                                                           \
    static  __table_extract_type INIT_FNS __table_entries[0]                  \
            __attribute__ (( __section__ ( __table_section ( INIT_FNS, 00 ) ),\
                 __aligned__ ( __table_alignment ( INIT_FNS ) ) ))            \
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn < ( {                                                           \
    static __table_extract_type INIT_FNS __table_entries[0]               
            __attribute__ (( __section__ ( __table_section ( INIT_FNS, 99 ) ),\
                 __aligned__ ( __table_alignment ( INIT_FNS ) ) ))
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn++ )

# 6
for ( init_fn = ( {                                                           \
    static  __table_extract_type INIT_FNS __table_entries[0]                  \
            __attribute__ (( __section__ ( ".tbl." __table_name ( INIT_FNS ) "." __table_str ( 00 ) ),\
                 __aligned__ ( __alignof__ ( __table_type ( INIT_FNS ) ) ) ))            \
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn < ( {                                                           \
    static __table_extract_type INIT_FNS __table_entries[0]               
            __attribute__ (( __section__ ( ".tbl." __table_name ( INIT_FNS ) "." __table_str ( 99 ),\
                 __aligned__ ( __alignof__ ( __table_type ( INIT_FNS ) ) ) ))
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn++ )

# 7
for ( init_fn = ( {                                                           \
    static  __table_extract_type INIT_FNS __table_entries[0]                  \
            __attribute__ (( __section__ ( ".tbl." __table_extract_name INIT_FNS "." #00 ),\
                 __aligned__ ( __alignof__ ( __table_extract_type INIT_FNS ) ) ))            \
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn < ( {                                                           \
    static __table_extract_type INIT_FNS __table_entries[0]               
            __attribute__ (( __section__ ( ".tbl." __table_extract_name INIT_FNS "." #99,\
                 __aligned__ ( __alignof__ ( __table_extract_type INIT_FNS ) ) ))
            __attribute__ (( unused ));                                       \
    __table_entries; } ) ;                                                    \
      init_fn++ )

Holy hell batman, I think that's it. I mean, it looks like there are more macros in there, so I may have messed up, but I don't see any object type macro definitions for

  • __table_extract_type
  • __table_extract_name
  • __table_entries
  • __attribute__
  • __aligned__
    • There is a def. for __aligned__attribute__, maybe I messed that up?
  • __section__
  • __alignof__

So was my expansion correct? And if so, how is this even valid code? Is this low level C/ASM stuff? I know the basics of assembly, but haven't used it in several years so I'm not sure what's going on here.

fuz
  • 88,405
  • 25
  • 200
  • 352
krb686
  • 1,726
  • 9
  • 26
  • 46
  • 2
    Why not get the compiler to do this for you? – Ed Heal Oct 21 '16 at 16:04
  • Good question, is there an option to have it dump expanded macros? I haven't done anything C related in years, and never anything like that. – krb686 Oct 21 '16 at 16:05
  • 5
    try `gcc -E `. But `__xx__` keywords won't expand, as they're not macros (gcc-specific directives?). – Jean-François Fabre Oct 21 '16 at 16:06
  • 1
    all __xx__ attributes you may found here: https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Function-Attributes.html#index-g_t_0040code_007bsection_007d-function-attribute-2579 , https://gcc.gnu.org/onlinedocs/gcc/Alignment.html – Laser Oct 21 '16 at 16:15
  • Doesn't look like you expanded the macros properly - there are macros for __table_extract_type, __table_extract_name, and __table_entries in the macro code that was posted. The C-preprocessor doesn't deal with *types* of macros, it is all just text. – Loring Oct 21 '16 at 16:26
  • Hmm, I read this last night: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/cpp/Macros.html, which says *"Object-like macros resemble data objects when used, function-like macros resemble function calls."* And then: *function-like macro* specific page, it says *"A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone."* It seems those macros you referred to are the *function-like* kind because they are defined with `()` directly after the name, and they are not referenced with `()` in the cases I left unexpanded. – krb686 Oct 21 '16 at 16:30
  • 1
    The `({ … })` notation is a GCC extension, statement expressions. – Jonathan Leffler Oct 21 '16 at 16:31
  • You might find the information in [Do function-like macros need mandatory parentheses?](http://stackoverflow.com/questions/40045529/) helpful. Someone else was recently confused about the paragraphs in the GCC manual that you're quoting in your comment. – Jonathan Leffler Oct 21 '16 at 22:52
  • Thanks for that link. After reading that question however, it looks like the OP was confused, but the GCC docs are not incorrect. The OP thought that the macro `#define FUNC display()` was a *function-like* macro, but it isn't, because ( and in accordance with the GCC docs) it doesn't have `()` directly after the macro name. It would be a *function-like* macro if it was `#define FUNC()...`. The macros above Loring referred to seem to be function-like, so I still don't see any inconsistency with those GCC docs, which state they are not expanded if they are not referenced with trailing `()` – krb686 Oct 21 '16 at 23:07

0 Answers0