@ -560,6 +560,23 @@ class Generator(object):
self . outln ( ' } ' )
self . outln ( ' } ' )
self . outln ( ' ' )
self . outln ( ' ' )
def write_ifunc ( self , func ) :
# Writes out the ifunc symbol that will have its PLT entry
# replaced with the resolved GL symbol when it's called.
# Tell the linker that even if we're in a static build, we need a PLT.
self . outln ( ' __asm__( " .type epoxy_ {0} , @gnu_indirect_function " ); ' . format ( func . name ) ) ;
# Tell the linker that epoxy_glWhatever() needs to be resolved
# by epoxy_ifunc_glWhatever().
self . outln ( ' void *epoxy_ifunc_ {0} (void) __asm__( " epoxy_ {0} " ); ' . format ( func . wrapped_name ) )
# Write out the actual epoxy_ifunc_glWhatever().
self . outln ( ' {0} void *epoxy_ifunc_ {1} (void) ' . format ( func . public , func . wrapped_name ) )
self . outln ( ' { ' )
self . outln ( ' return epoxy_ {0} _resolver(); ' . format ( func . alias_name ) )
self . outln ( ' } ' )
def write_provider_enums ( self ) :
def write_provider_enums ( self ) :
self . outln ( ' enum {0} _provider {{ ' . format ( self . target ) )
self . outln ( ' enum {0} _provider {{ ' . format ( self . target ) )
@ -634,6 +651,22 @@ class Generator(object):
self . outln ( ' #include " epoxy/ {0} .h " ' . format ( self . target ) )
self . outln ( ' #include " epoxy/ {0} .h " ' . format ( self . target ) )
self . outln ( ' ' )
self . outln ( ' ' )
# ifuncs are a newer-gcc and newer-dynamic-linker feature that
# let the library rewrite the application's PLT entry with our
# resolved function pointer.
#
# Note that dlsym() when we're called from the dynamic linker
# while it's loading libraries will break. So, libepoxy can't
# be loaded with RTLD_NOW when ifuncs are in use. We also
# can't use ifuncs for static builds, since static builds
# resolve just like RTLD_NOW.
self . outln ( ' #if defined(__PIC__) && defined(__linux__) ' )
self . outln ( ' #define USING_IFUNCS 1 ' )
self . outln ( ' #else ' )
self . outln ( ' #define USING_IFUNCS 0 ' )
self . outln ( ' #endif ' )
self . outln ( ' ' )
self . outln ( ' struct dispatch_table { ' )
self . outln ( ' struct dispatch_table { ' )
for func in self . sorted_functions :
for func in self . sorted_functions :
# Aliases don't get their own slot, since they use a shared resolver.
# Aliases don't get their own slot, since they use a shared resolver.
@ -646,9 +679,11 @@ class Generator(object):
# bottom. (I want the function_ptr_resolver as the first
# bottom. (I want the function_ptr_resolver as the first
# per-GL-call code, since it's the most interesting to see
# per-GL-call code, since it's the most interesting to see
# when you search for the implementation of a call)
# when you search for the implementation of a call)
self . outln ( ' #if !USING_IFUNCS ' )
self . outln ( ' static inline struct dispatch_table * ' )
self . outln ( ' static inline struct dispatch_table * ' )
self . outln ( ' get_dispatch_table(void); ' )
self . outln ( ' get_dispatch_table(void); ' )
self . outln ( ' ' )
self . outln ( ' ' )
self . outln ( ' #endif ' )
self . write_provider_enums ( )
self . write_provider_enums ( )
self . write_provider_enum_strings ( )
self . write_provider_enum_strings ( )
@ -658,6 +693,8 @@ class Generator(object):
if not func . alias_func :
if not func . alias_func :
self . write_function_ptr_resolver ( func )
self . write_function_ptr_resolver ( func )
self . outln ( ' #if !USING_IFUNCS ' )
for func in self . sorted_functions :
for func in self . sorted_functions :
if not func . alias_func :
if not func . alias_func :
self . write_dispatch_table_rewrite_stub ( func )
self . write_dispatch_table_rewrite_stub ( func )
@ -681,6 +718,13 @@ class Generator(object):
self . outln ( ' } ' )
self . outln ( ' } ' )
self . outln ( ' ' )
self . outln ( ' ' )
self . outln ( ' #else /* !USING_IFUNCS */ ' )
for func in self . sorted_functions :
self . write_ifunc ( func )
self . outln ( ' #endif /* !USING_IFUNCS */ ' )
argparser = argparse . ArgumentParser ( description = ' Generate GL dispatch wrappers. ' )
argparser = argparse . ArgumentParser ( description = ' Generate GL dispatch wrappers. ' )
argparser . add_argument ( ' files ' , metavar = ' file.xml ' , nargs = ' + ' , help = ' GL API XML files to be parsed ' )
argparser . add_argument ( ' files ' , metavar = ' file.xml ' , nargs = ' + ' , help = ' GL API XML files to be parsed ' )
argparser . add_argument ( ' --dir ' , metavar = ' dir ' , required = True , help = ' Destination directory ' )
argparser . add_argument ( ' --dir ' , metavar = ' dir ' , required = True , help = ' Destination directory ' )