Skip to content

Commit f8f073f

Browse files
committed
enable VA_ARGS wrapper functions, declare in headers
1 parent 7d2d3ec commit f8f073f

File tree

10 files changed

+272
-116
lines changed

10 files changed

+272
-116
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Features:
1313

1414
Limitations:
1515
* auto-loading only works on functions
16-
* auto-loading does not work on functions with variable arguments
16+
* auto-loading functions with variable arguments require GNU builtins (C only) and inlining
1717
* any type declaration more complicated than a function pointer will not be recognized
1818

1919

src/parameter_names.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ bool parse::get_parameter_names(proto_t &proto, param::names &parameter_names, s
155155
} else if (v.size() == 1) {
156156
/* check for `...' */
157157
if (v.front() == "...") {
158-
proto.notype_args += "... , ";
158+
/* don't append to proto.notype_args */
159159
continue;
160160
}
161161

src/substitute.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,6 @@ size_t gendlopen::replace_function_prototypes(const std::string &entry)
121121
}
122122

123123
for (auto &e : m_prototypes) {
124-
if (e.args.ends_with("...") && /* VA_ARGS */
125-
entry.find("%%return%%") != std::string::npos) /* wrapper function */
126-
{
127-
/* we can't handle variable argument lists in wrapper functions */
128-
continue;
129-
}
130-
131124
std::string copy = entry;
132125

133126
/* don't "return" on "void" functions */

src/templates/c.c

Lines changed: 19 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -739,35 +739,24 @@ GDO_INLINE char *_gdo_dladdr_get_fname(const void *ptr)
739739
/* wrap code */
740740
/*****************************************************************************/
741741

742-
/* #define empty hooks by default */
743-
#ifndef GDO_HOOK_%%func_symbol%%@
744-
#define GDO_HOOK_%%func_symbol%%(...) /**/@
745-
#endif
746-
747-
748-
#if (defined(GDO_WRAP_FUNCTIONS) || defined(GDO_ENABLE_AUTOLOAD)) && \
749-
defined(_WIN32) && defined(GDO_USE_MESSAGE_BOX)
750-
751-
GDO_INLINE void _gdo_show_MessageBox(const gdo_char_t *fmt, const gdo_char_t *sym, const gdo_char_t *msg)
752-
{
753-
gdo_char_t buf[GDO_BUFLEN];
754-
GDO_SNPRINTF(buf, fmt, sym, msg);
755-
MessageBox(NULL, buf, GDO_T("Error"), MB_OK | MB_ICONERROR);
756-
}
757-
758-
# define GDO_PRINT_ERROR(...) _gdo_show_MessageBox(__VA_ARGS__)
759-
742+
#if defined(_WIN32) && defined(GDO_USE_MESSAGE_BOX)
743+
# define GDO_PRINT_ERROR(...) \
744+
do { \
745+
gdo_char_t errbuf[GDO_BUFLEN]; \
746+
GDO_SNPRINTF(errbuf, __VA_ARGS__); \
747+
MessageBox(NULL, errbuf, GDO_T("Error"), MB_OK | MB_ICONERROR); \
748+
} while (0)
760749
#else
761-
762-
# define GDO_PRINT_ERROR(...) _gdo_ftprintf(stderr, __VA_ARGS__)
763-
750+
# define GDO_PRINT_ERROR(...) \
751+
do { \
752+
_gdo_ftprintf(stderr, __VA_ARGS__); \
753+
} while (0)
764754
#endif
765755

766756

767757
#if defined(GDO_WRAP_FUNCTIONS) && !defined(GDO_ENABLE_AUTOLOAD)
768758

769-
770-
GDO_INLINE void _gdo_wrap_check_if_loaded(bool sym_loaded, const gdo_char_t *sym)
759+
GDO_LINKAGE void _gdo_wrap_check_if_loaded(bool sym_loaded, const gdo_char_t *sym)
771760
{
772761
const gdo_char_t *msg;
773762

@@ -785,23 +774,11 @@ GDO_INLINE void _gdo_wrap_check_if_loaded(bool sym_loaded, const gdo_char_t *sym
785774
abort();
786775
}
787776

788-
789-
/* function wrappers (functions with `...' arguments are omitted) */
790-
791-
GDO_VISIBILITY %%type%% %%func_symbol%%(%%args%%) {@
792-
const bool sym_loaded = (gdo_hndl.ptr.%%func_symbol%% != NULL);@
793-
_gdo_wrap_check_if_loaded(sym_loaded, GDO_T("%%func_symbol%%"));@
794-
GDO_HOOK_%%func_symbol%%(%%notype_args%%);@
795-
%%return%% gdo_hndl.ptr.%%func_symbol%%(%%notype_args%%);@
796-
}@
797-
798-
799777
#elif defined(GDO_ENABLE_AUTOLOAD)
800778

801-
802779
/* This function is used by the autoload functions to perform the loading
803780
* and to handle errors. */
804-
GDO_INLINE void _gdo_quick_load(int symbol_num, const gdo_char_t *sym)
781+
GDO_LINKAGE void _gdo_quick_load(int symbol_num, const gdo_char_t *sym)
805782
{
806783
const gdo_char_t *fmt, *msg;
807784

@@ -848,31 +825,21 @@ GDO_INLINE void _gdo_quick_load(int symbol_num, const gdo_char_t *sym)
848825
exit(1);
849826
}
850827

851-
852-
/* autoload function wrappers (functions with `...' arguments are omitted) */
853-
854-
GDO_VISIBILITY %%type%% %%func_symbol%%(%%args%%) {@
855-
_gdo_quick_load(GDO_LOAD_%%func_symbol%%, GDO_T("%%func_symbol%%"));@
856-
GDO_HOOK_%%func_symbol%%(%%notype_args%%);@
857-
%%return%% gdo_hndl.ptr.%%func_symbol%%(%%notype_args%%);@
858-
}@
859-
860828
#endif //GDO_ENABLE_AUTOLOAD
861829
/***************************** end of wrap code ******************************/
862830
%PARAM_SKIP_END%
863831

864832

865-
#if !defined(GDO_SEPARATE) /* single header file */
833+
#if !defined(GDO_SEPARATE) && \
834+
!defined(GDO_DISABLE_ALIASING)
866835

867836
/* aliases to raw function pointers */
868-
#if !defined(GDO_DISABLE_ALIASING) && !defined(GDO_WRAP_FUNCTIONS) && !defined(GDO_ENABLE_AUTOLOAD)
869-
#define %%func_symbol_pad%% GDO_ALIAS_%%func_symbol%%
837+
#if !defined(GDO_WRAP_IS_VISIBLE)
838+
# define %%func_symbol_pad%% GDO_FUNC_ALIAS(%%func_symbol%%)
870839
#endif
871840

872841
/* aliases to raw object pointers */
873-
#if !defined(GDO_DISABLE_ALIASING)
874842
#define %%obj_symbol_pad%% GDO_ALIAS_%%obj_symbol%%
875-
#endif
876843

877844
#endif //!GDO_SEPARATE
878845

@@ -883,15 +850,13 @@ GDO_VISIBILITY %%type%% %%func_symbol%%(%%args%%) {@
883850
_gdo_clear_error \
884851
_gdo_dladdr_get_fname \
885852
_gdo_load_library \
886-
_gdo_show_MessageBox \
887-
_gdo_quick_load \
888853
_gdo_save_error \
889854
_gdo_save_to_errbuf \
890855
_gdo_set_error_no_library_loaded \
891-
_gdo_sym \
892-
_gdo_wrap_check_if_loaded
856+
_gdo_sym
893857
#endif //__GNUC__
894858

859+
#undef GDO_PRINT_ERROR
895860
#undef GDO_SET_LAST_ERRNO
896861
#undef GDO_SNPRINTF
897862

src/templates/c.h

Lines changed: 116 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,130 @@ GDO_DECL gdo_char_t *gdo_lib_origin(void)
200200
*/
201201
#define GDO_ALIAS_%%func_symbol_pad%% gdo_hndl.ptr.%%func_symbol%%
202202
#define GDO_ALIAS_%%obj_symbol_pad%% *gdo_hndl.ptr.%%obj_symbol%%
203+
%PARAM_SKIP_REMOVE_BEGIN%
203204

204205

206+
/*****************************************************************************/
207+
/* wrap code */
208+
/*****************************************************************************/
209+
#if defined(GDO_WRAP_FUNCTIONS) || defined(GDO_ENABLE_AUTOLOAD)
210+
211+
/* #define empty hooks by default */
212+
#ifndef GDO_HOOK_%%func_symbol%%@
213+
#define GDO_HOOK_%%func_symbol%%(...) /**/@
214+
#endif
215+
216+
217+
/* set visibility of wrapped functions */
218+
#ifdef GDO_WRAP_IS_VISIBLE
219+
/* visible as regular functions */
220+
# define GDO_WRAP_DECL /**/
221+
# define GDO_WRAP(x) x
222+
# else
223+
/* declare as prefixed inline functions by default */
224+
# define GDO_WRAP_DECL static inline
225+
# define GDO_WRAP(x) GDO_WRAP_##x
226+
#endif
227+
228+
229+
#ifdef GDO_ENABLE_AUTOLOAD
230+
/* autoload function */
231+
GDO_DECL void _gdo_quick_load(int symbol_num, const gdo_char_t *sym);
232+
# define GDO_WRAP_CHECK(x) _gdo_quick_load(GDO_LOAD_##x, GDO_T(#x))
233+
#else
234+
/* check if function was loaded */
235+
GDO_DECL void _gdo_wrap_check_if_loaded(bool sym_loaded, const gdo_char_t *sym);
236+
# define GDO_WRAP_CHECK(x) _gdo_wrap_check_if_loaded((gdo_hndl.ptr.x != NULL), GDO_T(#x))
237+
#endif
238+
239+
240+
/* create a wrapper function */
241+
#define GDO_MAKE_FUNCTION(RETURN, TYPE, SYMBOL, ARGS, ...) \
242+
GDO_WRAP_DECL \
243+
TYPE GDO_WRAP(SYMBOL) ARGS { \
244+
GDO_WRAP_CHECK(SYMBOL); \
245+
GDO_HOOK_##SYMBOL(__VA_ARGS__); \
246+
RETURN gdo_hndl.ptr.SYMBOL(__VA_ARGS__); \
247+
}
248+
205249
/**
206-
* Disable aliasing if we saved into separate files and the
207-
* header file was included from the body file.
250+
* create a GNU inline wrapper function for use with variable arguments
251+
* https://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html
208252
*/
209-
#if defined(GDO_SEPARATE) && !defined(GDO_INCLUDED_IN_BODY) && !defined(GDO_DISABLE_ALIASING)
253+
#define GDO_MAKE_VA_ARG_FUNCTION(RETURN, TYPE, SYMBOL, ARGS, ...) \
254+
extern inline __attribute__((__gnu_inline__)) \
255+
TYPE GDO_WRAP(SYMBOL) ARGS { \
256+
GDO_WRAP_CHECK(SYMBOL); \
257+
GDO_HOOK_##SYMBOL(__VA_ARGS__, __builtin_va_arg_pack()); \
258+
RETURN gdo_hndl.ptr.SYMBOL(__VA_ARGS__, __builtin_va_arg_pack()); \
259+
}
260+
261+
262+
/* diagnostic warnings on variable arguments functions */
263+
#if !defined(GDO_DISABLE_WARNINGS)
264+
265+
#ifdef GDO_HAS_VA_ARGS_%%func_symbol%%@
266+
# ifdef GDO_HAS_BUILTIN_VA_ARG_PACK@
267+
# ifdef GDO_WRAP_IS_VISIBLE@
268+
# warning "%%func_symbol%%: GDO_WRAP_IS_VISIBLE defined but function can only be used inlined"@
269+
# endif@
270+
# else@
271+
# warning "%%func_symbol%%: __builtin_va_arg_pack() required to use variable arguments wrapper"@
272+
# endif@
273+
#endif
274+
275+
#endif //!GDO_DISABLE_WARNINGS
276+
277+
@
278+
/* %%func_symbol%%() */@
279+
#ifdef GDO_HAS_VA_ARGS_%%func_symbol%%@
280+
# ifdef GDO_HAS_BUILTIN_VA_ARG_PACK@
281+
GDO_MAKE_VA_ARG_FUNCTION(%%return%%, %%type%%,@
282+
%%func_symbol%%, (%%args%%),@
283+
%%notype_args%%)@
284+
# endif@
285+
#else@
286+
GDO_MAKE_FUNCTION(%%return%%, %%type%%,@
287+
%%func_symbol%%, (%%args%%),@
288+
%%notype_args%%)@
289+
#endif //!GDO_HAS_VA_ARGS_%%func_symbol%%@
290+
291+
292+
#undef GDO_WRAP_DECL
293+
#undef GDO_WRAP
294+
#undef GDO_WRAP_CHECK
295+
#undef GDO_MAKE_FUNCTION
296+
#undef GDO_MAKE_VA_ARG_FUNCTION
297+
298+
#endif //GDO_WRAP_FUNCTIONS ...
299+
/***************************** end of wrap code ******************************/
300+
%PARAM_SKIP_END%
301+
302+
303+
/**
304+
* Set function name alias prefix.
305+
*/
306+
#if defined(GDO_WRAP_FUNCTIONS) || defined(GDO_ENABLE_AUTOLOAD)
307+
# define GDO_FUNC_ALIAS(x) GDO_WRAP_##x
308+
#else
309+
# define GDO_FUNC_ALIAS(x) GDO_ALIAS_##x
310+
#endif
311+
210312

211313
/**
212-
* Aliases to raw pointers
314+
* Disable aliasing if we saved into separate files and the
315+
* header file was included from the body file.
213316
*/
214-
#if !defined(GDO_WRAP_FUNCTIONS) && !defined(GDO_ENABLE_AUTOLOAD)
215-
#define %%func_symbol_pad%% GDO_ALIAS_%%func_symbol%%
317+
#if defined(GDO_SEPARATE) && \
318+
!defined(GDO_INCLUDED_IN_BODY) && \
319+
!defined(GDO_DISABLE_ALIASING)
320+
321+
/* aliases to raw function pointers */
322+
#if !defined(GDO_WRAP_IS_VISIBLE)
323+
# define %%func_symbol_pad%% GDO_FUNC_ALIAS(%%func_symbol%%)
216324
#endif
325+
326+
/* aliases to raw object pointers */
217327
#define %%obj_symbol_pad%% GDO_ALIAS_%%obj_symbol%%
218328

219329
#endif //GDO_SEPARATE ...

src/templates/common.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ GDO_STATIC
1515
If defined `static inline' linkage is used for all functions.
1616
1717
GDO_WRAP_FUNCTIONS
18-
Use actual wrapped functions instead of a name alias.
18+
Use actual function wrappers instead of a name alias.
19+
20+
GDO_WRAP_IS_VISIBLE
21+
Declare function wrappers as regular visible functions instead of inlining them.
1922
2023
GDO_ENABLE_AUTOLOAD
2124
Define this macro if you want to use auto-loading wrapper functions.
@@ -32,6 +35,9 @@ GDO_USE_MESSAGE_BOX
3235
GDO_DISABLE_ALIASING
3336
Don't use preprocessor macros to alias symbol names.
3437
38+
GDO_DISABLE_WARNINGS
39+
Mute diagnostic warnings.
40+
3541
3642
*** settings ***
3743
@@ -143,6 +149,14 @@ typedef Dl_info _GDO_Dl_info;
143149
#endif
144150

145151

152+
/* check for __builtin_va_arg_pack() */
153+
#if !defined(GDO_HAS_BUILTIN_VA_ARG_PACK) && defined(__has_builtin)
154+
# if __has_builtin(__builtin_va_arg_pack)
155+
# define GDO_HAS_BUILTIN_VA_ARG_PACK
156+
# endif
157+
#endif
158+
159+
146160
/* default library name */
147161

148162
#if defined(GDO_WINAPI) && defined(_UNICODE)

0 commit comments

Comments
 (0)