MEDIUM: init: convert all trivial registration calls to initcalls

This switches explicit calls to various trivial registration methods for
keywords, muxes or protocols from constructors to INITCALL1 at stage
STG_REGISTER. All these calls have in common to consume a single pointer
and return void. Doing this removes 26 constructors. The following calls
were addressed :

- acl_register_keywords
- bind_register_keywords
- cfg_register_keywords
- cli_register_kw
- flt_register_keywords
- http_req_keywords_register
- http_res_keywords_register
- protocol_register
- register_mux_proto
- sample_register_convs
- sample_register_fetches
- srv_register_keywords
- tcp_req_conn_keywords_register
- tcp_req_cont_keywords_register
- tcp_req_sess_keywords_register
- tcp_res_cont_keywords_register
- flt_register_keywords
diff --git a/doc/internals/filters.txt b/doc/internals/filters.txt
index 61a0155..09090e5 100644
--- a/doc/internals/filters.txt
+++ b/doc/internals/filters.txt
@@ -353,13 +353,7 @@
             { NULL, NULL, NULL },
         }
     };
-
-    __attribute__((constructor))
-    static void
-    __my_filter_init(void)
-    {
-        flt_register_keywords(&flt_kws);
-    }
+    INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
 
 
 Then you must define the internal configuration your filter will use. For
diff --git a/src/51d.c b/src/51d.c
index e092c5b..d537964 100644
--- a/src/51d.c
+++ b/src/51d.c
@@ -4,6 +4,7 @@
 #include <common/chunk.h>
 #include <common/buffer.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <proto/arg.h>
 #include <proto/http_fetch.h>
 #include <proto/log.h>
@@ -667,25 +668,28 @@
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &_51dcfg_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 	{ "51d.all", _51d_fetch, ARG5(1,STR,STR,STR,STR,STR), _51d_fetch_check, SMP_T_STR, SMP_USE_HRQHV },
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list conv_kws = {ILH, {
 	{ "51d.single", _51d_conv, ARG5(1,STR,STR,STR,STR,STR), _51d_conv_check, SMP_T_STR, SMP_T_STR },
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws);
+
 __attribute__((constructor))
 static void __51d_init(void)
 {
 	/* register sample fetch and conversion keywords */
-	sample_register_fetches(&sample_fetch_keywords);
-	sample_register_convs(&conv_kws);
-	cfg_register_keywords(&_51dcfg_kws);
 	hap_register_build_opts("Built with 51Degrees support.", 0);
 	hap_register_post_check(init_51degrees);
 	hap_register_post_deinit(deinit_51degrees);
diff --git a/src/acl.c b/src/acl.c
index a9cf7a1..b598088 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -15,6 +15,7 @@
 #include <string.h>
 
 #include <common/config.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/uri_auth.h>
@@ -1352,12 +1353,7 @@
 	{ /* END */ },
 }};
 
-__attribute__((constructor))
-static void __acl_init(void)
-{
-	acl_register_keywords(&acl_kws);
-}
-
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
 
 /*
  * Local variables:
diff --git a/src/activity.c b/src/activity.c
index 9460a8a..4a807c8 100644
--- a/src/activity.c
+++ b/src/activity.c
@@ -14,6 +14,7 @@
 #include <common/config.h>
 #include <common/standard.h>
 #include <common/hathreads.h>
+#include <common/initcall.h>
 #include <types/activity.h>
 #include <proto/channel.h>
 #include <proto/cli.h>
@@ -116,6 +117,8 @@
 	{ 0, NULL, NULL }
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
 	{ { "show", "profiling", NULL }, "show profiling : show CPU profiling options",   NULL, cli_io_handler_show_profiling, NULL },
@@ -123,9 +126,4 @@
 	{{},}
 }};
 
-__attribute__((constructor))
-static void __activity_init(void)
-{
-	cfg_register_keywords(&cfg_kws);
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
diff --git a/src/backend.c b/src/backend.c
index e55d87c..5aaa46d 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -24,6 +24,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/hash.h>
+#include <common/initcall.h>
 #include <common/ticks.h>
 #include <common/time.h>
 #include <common/namespace.h>
@@ -2073,12 +2074,15 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
 	{ "nbsrv", sample_conv_nbsrv, 0, NULL, SMP_T_STR, SMP_T_SINT },
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
 
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
@@ -2087,14 +2091,7 @@
 	{ /* END */ },
 }};
 
-
-__attribute__((constructor))
-static void __backend_init(void)
-{
-	sample_register_fetches(&smp_kws);
-	sample_register_convs(&sample_conv_kws);
-	acl_register_keywords(&acl_kws);
-}
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
 
 /*
  * Local variables:
diff --git a/src/cache.c b/src/cache.c
index 2157433..acab99d 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -34,6 +34,7 @@
 
 #include <common/cfgparse.h>
 #include <common/hash.h>
+#include <common/initcall.h>
 
 /* flt_cache_store */
 
@@ -1184,6 +1185,7 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 static struct action_kw_list http_res_actions = {
 	.kw = {
@@ -1192,6 +1194,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
+
 static struct action_kw_list http_req_actions = {
 	.kw = {
 		{ "cache-use", parse_cache_use },
@@ -1199,6 +1203,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
+
 struct applet http_cache_applet = {
 	.obj_type = OBJ_TYPE_APPLET,
 	.name = "<CACHE>", /* used for logging */
@@ -1211,9 +1217,5 @@
 {
 	cfg_register_section("cache", cfg_parse_cache, cfg_post_parse_section_cache);
 	cfg_register_postparser("cache", cfg_cache_postparser);
-	cli_register_kw(&cli_kws);
-	http_res_keywords_register(&http_res_actions);
-	http_req_keywords_register(&http_req_actions);
 	pool_head_cache_st = create_pool("cache_st", sizeof(struct cache_st), MEM_F_SHARED);
 }
-
diff --git a/src/cli.c b/src/cli.c
index 3f43862..b8b2335 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -30,6 +30,7 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -2449,11 +2450,15 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
+
 static struct cfg_kw_list cfg_kws = {ILH, {
 	{ CFG_GLOBAL, "stats", stats_parse_global },
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 static struct bind_kw_list bind_kws = { "STAT", { }, {
 	{ "level",     bind_parse_level,    1 }, /* set the unix socket admin level */
 	{ "expose-fd", bind_parse_expose_fd, 1 }, /* set the unix socket expose fd rights */
@@ -2461,13 +2466,7 @@
 	{ NULL, NULL, 0 },
 }};
 
-__attribute__((constructor))
-static void __dumpstats_module_init(void)
-{
-	cfg_register_keywords(&cfg_kws);
-	cli_register_kw(&cli_kws);
-	bind_register_keywords(&bind_kws);
-}
+INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
 
 /*
  * Local variables:
diff --git a/src/compression.c b/src/compression.c
index d3e6f28..b725e31 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -28,8 +28,9 @@
 
 #include <common/cfgparse.h>
 #include <common/compat.h>
-#include <common/memory.h>
 #include <common/hathreads.h>
+#include <common/initcall.h>
+#include <common/memory.h>
 
 #include <types/global.h>
 #include <types/compression.h>
@@ -699,6 +700,8 @@
 	{ 0, NULL, NULL }
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 __attribute__((constructor))
 static void __comp_fetch_init(void)
 {
@@ -735,5 +738,4 @@
 		memprintf(&ptr, "%s none", ptr);
 
 	hap_register_build_opts(ptr, 1);
-	cfg_register_keywords(&cfg_kws);
 }
diff --git a/src/connection.c b/src/connection.c
index 5022772..6214775 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -14,6 +14,7 @@
 
 #include <common/compat.h>
 #include <common/config.h>
+#include <common/initcall.h>
 #include <common/namespace.h>
 #include <common/hash.h>
 #include <common/net_helper.h>
@@ -1314,9 +1315,4 @@
 	{ /* END */ },
 }};
 
-
-__attribute__((constructor))
-static void __connection_init(void)
-{
-	sample_register_fetches(&sample_fetch_keywords);
-}
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
diff --git a/src/da.c b/src/da.c
index 990267a..c1c07e3 100644
--- a/src/da.c
+++ b/src/da.c
@@ -3,6 +3,7 @@
 #include <common/cfgparse.h>
 #include <common/errors.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <proto/arg.h>
 #include <proto/http_fetch.h>
 #include <proto/log.h>
@@ -376,25 +377,28 @@
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &dacfg_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_fetch_kw_list fetch_kws = {ILH, {
 	{ "da-csv-fetch", da_haproxy_fetch, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list conv_kws = {ILH, {
 	{ "da-csv-conv", da_haproxy_conv, ARG12(1,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws);
+
 __attribute__((constructor))
 static void __da_init(void)
 {
 	/* register sample fetch and format conversion keywords */
-	sample_register_fetches(&fetch_kws);
-	sample_register_convs(&conv_kws);
-	cfg_register_keywords(&dacfg_kws);
 	hap_register_build_opts("Built with DeviceAtlas support.", 0);
 	hap_register_post_check(init_deviceatlas);
 	hap_register_post_deinit(deinit_deviceatlas);
diff --git a/src/dns.c b/src/dns.c
index 5bce18b..2dfbdd5 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -21,6 +21,7 @@
 
 #include <common/cfgparse.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/time.h>
 #include <common/ticks.h>
 #include <common/net_helper.h>
@@ -2050,6 +2051,7 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 __attribute__((constructor))
 static void __dns_init(void)
@@ -2059,6 +2061,4 @@
 
 	cfg_register_postparser("dns runtime resolver", dns_finalize_config);
 	hap_register_post_deinit(dns_deinit);
-
-	cli_register_kw(&cli_kws);
 }
diff --git a/src/filters.c b/src/filters.c
index bdc106a..edce603 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -16,6 +16,7 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/namespace.h>
 #include <common/standard.h>
 #include <common/hathreads.h>
@@ -1189,12 +1190,13 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 __attribute__((constructor))
 static void
 __filters_init(void)
 {
         pool_head_filter = create_pool("filter", sizeof(struct filter), MEM_F_SHARED);
-	cfg_register_keywords(&cfg_kws);
 	hap_register_post_check(flt_init_all);
 	hap_register_per_thread_init(flt_init_all_per_thread);
 	hap_register_per_thread_deinit(flt_deinit_all_per_thread);
diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
index b4f093c..e0cee75 100644
--- a/src/flt_http_comp.c
+++ b/src/flt_http_comp.c
@@ -12,6 +12,7 @@
 
 #include <common/buffer.h>
 #include <common/cfgparse.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 
@@ -993,6 +994,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 /* Declare the filter parser for "compression" keyword */
 static struct flt_kw_list filter_kws = { "COMP", { }, {
 		{ "compression", parse_http_comp_flt, NULL },
@@ -1000,6 +1003,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, flt_register_keywords, &filter_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 		{ "res.comp",      smp_fetch_res_comp,      0, NULL, SMP_T_BOOL, SMP_USE_HRSHP },
@@ -1008,12 +1013,11 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
+
 __attribute__((constructor))
 static void
 __flt_http_comp_init(void)
 {
-	cfg_register_keywords(&cfg_kws);
-	flt_register_keywords(&filter_kws);
-	sample_register_fetches(&sample_fetch_keywords);
 	pool_head_comp_state = create_pool("comp_state", sizeof(struct comp_state), MEM_F_SHARED);
 }
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 02bc3d2..aa9d875 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -16,9 +16,10 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
+#include <common/hathreads.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/time.h>
-#include <common/hathreads.h>
 
 #include <types/arg.h>
 #include <types/global.h>
@@ -4641,37 +4642,44 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
+
 /* Delcate the action parser for "spoe-action" keyword */
 static struct action_kw_list tcp_req_action_kws = { { }, {
 		{ "send-spoe-group", parse_send_spoe_group },
 		{ /* END */ },
 	}
 };
+
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_action_kws);
+
 static struct action_kw_list tcp_res_action_kws = { { }, {
 		{ "send-spoe-group", parse_send_spoe_group },
 		{ /* END */ },
 	}
 };
+
+INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_action_kws);
+
 static struct action_kw_list http_req_action_kws = { { }, {
 		{ "send-spoe-group", parse_send_spoe_group },
 		{ /* END */ },
 	}
 };
+
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_action_kws);
+
 static struct action_kw_list http_res_action_kws = { { }, {
 		{ "send-spoe-group", parse_send_spoe_group },
 		{ /* END */ },
 	}
 };
 
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_action_kws);
+
 __attribute__((constructor))
 static void __spoe_init(void)
 {
-	flt_register_keywords(&flt_kws);
-	tcp_req_cont_keywords_register(&tcp_req_action_kws);
-	tcp_res_cont_keywords_register(&tcp_res_action_kws);
-	http_req_keywords_register(&http_req_action_kws);
-	http_res_keywords_register(&http_res_action_kws);
-
 	pool_head_spoe_ctx = create_pool("spoe_ctx", sizeof(struct spoe_context), MEM_F_SHARED);
 	pool_head_spoe_appctx = create_pool("spoe_appctx", sizeof(struct spoe_appctx), MEM_F_SHARED);
 }
diff --git a/src/flt_trace.c b/src/flt_trace.c
index 6b65fe9..d5a4d93 100644
--- a/src/flt_trace.c
+++ b/src/flt_trace.c
@@ -12,10 +12,11 @@
 
 #include <ctype.h>
 
+#include <common/hathreads.h>
+#include <common/initcall.h>
 #include <common/standard.h>
 #include <common/time.h>
 #include <common/tools.h>
-#include <common/hathreads.h>
 
 #include <types/channel.h>
 #include <types/filters.h>
@@ -628,9 +629,4 @@
 	}
 };
 
-__attribute__((constructor))
-static void
-__flt_trace_init(void)
-{
-	flt_register_keywords(&flt_kws);
-}
+INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
diff --git a/src/frontend.c b/src/frontend.c
index 65c6966..7167257 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -26,6 +26,7 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
+#include <common/initcall.h>
 #include <common/standard.h>
 #include <common/time.h>
 
@@ -263,6 +264,7 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
 
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
@@ -271,14 +273,7 @@
 	{ /* END */ },
 }};
 
-
-__attribute__((constructor))
-static void __frontend_init(void)
-{
-	sample_register_fetches(&smp_kws);
-	acl_register_keywords(&acl_kws);
-}
-
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
 
 /*
  * Local variables:
diff --git a/src/hlua.c b/src/hlua.c
index c354af8..d34aa79 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -26,8 +26,9 @@
 
 #include <common/cfgparse.h>
 #include <common/compiler.h>
-#include <common/xref.h>
 #include <common/hathreads.h>
+#include <common/initcall.h>
+#include <common/xref.h>
 
 #include <types/cli.h>
 #include <types/hlua.h>
@@ -7520,6 +7521,8 @@
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 static int hlua_check_config()
 {
 	struct proxy *px;
@@ -7672,9 +7675,6 @@
 	/* Initialise struct hlua and com signals pool */
 	pool_head_hlua = create_pool("hlua", sizeof(struct hlua), MEM_F_SHARED);
 
-	/* Register configuration keywords. */
-	cfg_register_keywords(&cfg_kws);
-
 	/* Init main lua stack. */
 	gL.Mref = LUA_REFNIL;
 	gL.flags = 0;
diff --git a/src/http_acl.c b/src/http_acl.c
index 7864df8..edd3be5 100644
--- a/src/http_acl.c
+++ b/src/http_acl.c
@@ -21,6 +21,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/standard.h>
 #include <common/version.h>
@@ -180,11 +181,7 @@
 	{ /* END */ },
 }};
 
-__attribute__((constructor))
-static void __http_acl_init(void)
-{
-	acl_register_keywords(&acl_kws);
-}
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
 
 /*
  * Local variables:
diff --git a/src/http_act.c b/src/http_act.c
index 8ca6ba4..37cf435 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -21,6 +21,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/standard.h>
 #include <common/version.h>
@@ -586,6 +587,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
+
 static struct action_kw_list http_res_actions = {
 	.kw = {
 		{ "capture",    parse_http_res_capture },
@@ -594,12 +597,7 @@
 	}
 };
 
-__attribute__((constructor))
-static void __http_act_init(void)
-{
-	http_req_keywords_register(&http_req_actions);
-	http_res_keywords_register(&http_res_actions);
-}
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
 
 /*
  * Local variables:
diff --git a/src/http_conv.c b/src/http_conv.c
index c6cfdab..93b748c 100644
--- a/src/http_conv.c
+++ b/src/http_conv.c
@@ -21,6 +21,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/standard.h>
 #include <common/version.h>
@@ -335,11 +336,7 @@
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
-__attribute__((constructor))
-static void __http_conv_init(void)
-{
-	sample_register_convs(&sample_conv_kws);
-}
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
 
 /*
  * Local variables:
diff --git a/src/http_fetch.c b/src/http_fetch.c
index 56c6a2b..3890509 100644
--- a/src/http_fetch.c
+++ b/src/http_fetch.c
@@ -22,6 +22,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/standard.h>
 #include <common/version.h>
@@ -2851,12 +2852,7 @@
 	{ /* END */ },
 }};
 
-
-__attribute__((constructor))
-static void __http_fetch_init(void)
-{
-	sample_register_fetches(&sample_fetch_keywords);
-}
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
 
 /*
  * Local variables:
diff --git a/src/listener.c b/src/listener.c
index a730b18..2a38cfd 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -22,6 +22,7 @@
 #include <common/cfgparse.h>
 #include <common/config.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/time.h>
@@ -1013,6 +1014,8 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
  */
@@ -1020,6 +1023,8 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted, doing so helps
  * all code contributors.
@@ -1040,12 +1045,11 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
+
 __attribute__((constructor))
 static void __listener_init(void)
 {
-	sample_register_fetches(&smp_kws);
-	acl_register_keywords(&acl_kws);
-	bind_register_keywords(&bind_kws);
 	HA_SPIN_INIT(&lq_lock);
 }
 
diff --git a/src/log.c b/src/log.c
index 3db3c0d..5c6b8df 100644
--- a/src/log.c
+++ b/src/log.c
@@ -26,6 +26,7 @@
 
 #include <common/config.h>
 #include <common/compat.h>
+#include <common/initcall.h>
 #include <common/standard.h>
 #include <common/time.h>
 
@@ -2806,12 +2807,13 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
+
 __attribute__((constructor))
 static void __log_init(void)
 {
 	hap_register_per_thread_init(init_log_buffers_per_thread);
 	hap_register_per_thread_deinit(deinit_log_buffers_per_thread);
-	cli_register_kw(&cli_kws);
 }
 /*
  * Local variables:
diff --git a/src/map.c b/src/map.c
index 7eb9e36..bfdb73d 100644
--- a/src/map.c
+++ b/src/map.c
@@ -13,6 +13,7 @@
 #include <limits.h>
 #include <stdio.h>
 
+#include <common/initcall.h>
 #include <common/standard.h>
 
 #include <types/applet.h>
@@ -1106,6 +1107,7 @@
 	{ { NULL }, NULL, NULL, NULL }
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 /* Note: must not be declared <const> as its list will be overwritten
  *
@@ -1159,10 +1161,4 @@
 	{ /* END */ },
 }};
 
-__attribute__((constructor))
-static void __map_init(void)
-{
-	/* register format conversion keywords */
-	sample_register_convs(&sample_conv_kws);
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
diff --git a/src/memory.c b/src/memory.c
index 17ac1d1..1554243 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -18,6 +18,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/hathreads.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -526,11 +527,7 @@
 	{{},}
 }};
 
-__attribute__((constructor))
-static void __memory_init(void)
-{
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 /*
  * Local variables:
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 2e28d36..c9bfaa3 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -11,6 +11,7 @@
  */
 #include <common/cfgparse.h>
 #include <common/config.h>
+#include <common/initcall.h>
 
 #include <types/pipe.h>
 #include <types/proxy.h>
@@ -1823,6 +1824,8 @@
 static struct mux_proto_list mux_proto_htx =
 { .token = IST(""), .mode = PROTO_MODE_HTX, .side = PROTO_SIDE_BOTH, .mux = &mux_h1_ops };
 
+INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_htx);
+
 static void __h1_deinit(void)
 {
 	pool_destroy(pool_head_h1c);
@@ -1832,7 +1835,6 @@
 __attribute__((constructor))
 static void __h1_init(void)
 {
-	register_mux_proto(&mux_proto_htx);
 	hap_register_post_deinit(__h1_deinit);
 	pool_head_h1c = create_pool("h1c", sizeof(struct h1c), MEM_F_SHARED);
 	pool_head_h1s = create_pool("h1s", sizeof(struct h1s), MEM_F_SHARED);
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 0407e38..c3cd1e1 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -16,6 +16,7 @@
 #include <common/hpack-dec.h>
 #include <common/hpack-enc.h>
 #include <common/hpack-tbl.h>
+#include <common/initcall.h>
 #include <common/net_helper.h>
 #include <proto/connection.h>
 #include <proto/h1.h>
@@ -3832,6 +3833,8 @@
 static struct mux_proto_list mux_proto_h2 =
 	{ .token = IST("h2"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_FE, .mux = &h2_ops };
 
+INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_h2);
+
 /* config keyword parsers */
 static struct cfg_kw_list cfg_kws = {ILH, {
 	{ CFG_GLOBAL, "tune.h2.header-table-size",      h2_parse_header_table_size      },
@@ -3840,6 +3843,8 @@
 	{ 0, NULL, NULL }
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 static void __h2_deinit(void)
 {
 	pool_destroy(pool_head_h2s);
@@ -3849,8 +3854,6 @@
 __attribute__((constructor))
 static void __h2_init(void)
 {
-	register_mux_proto(&mux_proto_h2);
-	cfg_register_keywords(&cfg_kws);
 	hap_register_post_deinit(__h2_deinit);
 	pool_head_h2c = create_pool("h2c", sizeof(struct h2c), MEM_F_SHARED);
 	pool_head_h2s = create_pool("h2s", sizeof(struct h2s), MEM_F_SHARED);
diff --git a/src/mux_pt.c b/src/mux_pt.c
index a974ec3..8e9c651 100644
--- a/src/mux_pt.c
+++ b/src/mux_pt.c
@@ -11,6 +11,7 @@
  */
 
 #include <common/config.h>
+#include <common/initcall.h>
 #include <proto/connection.h>
 #include <proto/stream.h>
 #include <proto/task.h>
@@ -316,10 +317,11 @@
 static struct mux_proto_list mux_proto_pt =
 	{ .token = IST(""), .mode = PROTO_MODE_ANY, .side = PROTO_SIDE_BOTH, .mux = &mux_pt_ops };
 
+INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_pt);
+
 __attribute__((constructor))
 static void __mux_pt_init(void)
 {
-	register_mux_proto(&mux_proto_pt);
 	pool_head_pt_ctx = create_pool("mux_pt", sizeof(struct mux_pt_ctx),
 	    MEM_F_SHARED);
 }
diff --git a/src/payload.c b/src/payload.c
index 054168a..14191a7 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -13,6 +13,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <common/initcall.h>
 #include <common/net_helper.h>
 #include <proto/acl.h>
 #include <proto/arg.h>
@@ -1151,6 +1152,7 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
 
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
@@ -1166,13 +1168,7 @@
 	{ /* END */ },
 }};
 
-
-__attribute__((constructor))
-static void __payload_init(void)
-{
-	sample_register_fetches(&smp_kws);
-	acl_register_keywords(&acl_kws);
-}
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
 
 /*
  * Local variables:
diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c
index ba82c5e..ef0e725 100644
--- a/src/proto_sockpair.c
+++ b/src/proto_sockpair.c
@@ -30,6 +30,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/time.h>
@@ -74,6 +75,8 @@
 	.nb_listeners = 0,
 };
 
+INITCALL1(STG_REGISTER, protocol_register, &proto_sockpair);
+
 /* Add <listener> to the list of sockpair listeners (port is ignored). The
  * listener's state is automatically updated from LI_INIT to LI_ASSIGNED.
  * The number of listeners for the protocol is updated.
@@ -389,12 +392,6 @@
 	return recv_fd;
 }
 
-__attribute__((constructor))
-static void __uxst_protocol_init(void)
-{
-	protocol_register(&proto_sockpair);
-}
-
 /*
  * Local variables:
  *  c-indent-level: 8
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index c7951c5..2692668 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -36,6 +36,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/namespace.h>
@@ -90,6 +91,8 @@
 	.nb_listeners = 0,
 };
 
+INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv4);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_tcpv6 = {
 	.name = "tcpv6",
@@ -113,6 +116,8 @@
 	.nb_listeners = 0,
 };
 
+INITCALL1(STG_REGISTER, protocol_register, &proto_tcpv6);
+
 /* Default TCP parameters, got by opening a temporary TCP socket. */
 #ifdef TCP_MAXSEG
 static THREAD_LOCAL int default_tcp_maxseg = -1;
@@ -1913,6 +1918,8 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
+
 /************************************************************************/
 /*           All supported bind keywords must be declared here.         */
 /************************************************************************/
@@ -1960,6 +1967,8 @@
 	{ NULL, NULL, 0 },
 }};
 
+INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
+
 static struct srv_kw_list srv_kws = { "TCP", { }, {
 #ifdef TCP_USER_TIMEOUT
 	{ "tcp-ut",        srv_parse_tcp_ut,        1,  1 }, /* set TCP user timeout on server */
@@ -1967,6 +1976,8 @@
 	{ NULL, NULL, 0 },
 }};
 
+INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
+
 static struct action_kw_list tcp_req_conn_actions = {ILH, {
 	{ "silent-drop",  tcp_parse_silent_drop },
 	{ "set-src",      tcp_parse_set_src_dst },
@@ -1976,6 +1987,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
+
 static struct action_kw_list tcp_req_sess_actions = {ILH, {
 	{ "silent-drop",  tcp_parse_silent_drop },
 	{ "set-src",      tcp_parse_set_src_dst },
@@ -1985,16 +1998,22 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions);
+
 static struct action_kw_list tcp_req_cont_actions = {ILH, {
 	{ "silent-drop", tcp_parse_silent_drop },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions);
+
 static struct action_kw_list tcp_res_cont_actions = {ILH, {
 	{ "silent-drop", tcp_parse_silent_drop },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions);
+
 static struct action_kw_list http_req_actions = {ILH, {
 	{ "silent-drop",  tcp_parse_silent_drop },
 	{ "set-src",      tcp_parse_set_src_dst },
@@ -2004,28 +2023,18 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
+
 static struct action_kw_list http_res_actions = {ILH, {
 	{ "silent-drop", tcp_parse_silent_drop },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
 
 __attribute__((constructor))
 static void __tcp_protocol_init(void)
 {
-	protocol_register(&proto_tcpv4);
-	protocol_register(&proto_tcpv6);
-	sample_register_fetches(&sample_fetch_keywords);
-	bind_register_keywords(&bind_kws);
-	srv_register_keywords(&srv_kws);
-	tcp_req_conn_keywords_register(&tcp_req_conn_actions);
-	tcp_req_sess_keywords_register(&tcp_req_sess_actions);
-	tcp_req_cont_keywords_register(&tcp_req_cont_actions);
-	tcp_res_cont_keywords_register(&tcp_res_cont_actions);
-	http_req_keywords_register(&http_req_actions);
-	http_res_keywords_register(&http_res_actions);
-
-
 	hap_register_build_opts("Built with transparent proxy support using:"
 #if defined(IP_TRANSPARENT)
 	       " IP_TRANSPARENT"
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 149ba8e..878a10d 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -30,6 +30,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/time.h>
@@ -77,6 +78,8 @@
 	.nb_listeners = 0,
 };
 
+INITCALL1(STG_REGISTER, protocol_register, &proto_unix);
+
 /********************************
  * 1) low-level socket functions
  ********************************/
@@ -720,17 +723,7 @@
 	{ NULL, NULL, 0 },
 }};
 
-/********************************
- * 4) high-level functions
- ********************************/
-
-__attribute__((constructor))
-static void __uxst_protocol_init(void)
-{
-	protocol_register(&proto_unix);
-	bind_register_keywords(&bind_kws);
-}
-
+INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
 
 /*
  * Local variables:
diff --git a/src/proxy.c b/src/proxy.c
index 76d84a2..f8d22b6 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -22,6 +22,7 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/time.h>
 
@@ -1497,6 +1498,8 @@
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 /* Expects to find a frontend named <arg> and returns it, otherwise displays various
  * adequate error messages and returns NULL. This function is designed to be used by
  * functions requiring a frontend on the CLI.
@@ -2229,12 +2232,7 @@
 	{{},}
 }};
 
-__attribute__((constructor))
-static void __proxy_module_init(void)
-{
-	cfg_register_keywords(&cfg_kws);
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 /*
  * Local variables:
diff --git a/src/queue.c b/src/queue.c
index a5f129d..fa02b4a 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -70,6 +70,7 @@
  */
 
 #include <common/config.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/time.h>
 #include <common/hathreads.h>
@@ -601,12 +602,16 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_cont_kws);
+
 static struct action_kw_list http_req_kws = {ILH, {
 	{ "set-priority-class", parse_set_priority_class },
 	{ "set-priority-offset", parse_set_priority_offset },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
+
 static int
 smp_fetch_priority_class(const struct arg *args, struct sample *smp, const char *kw, void *private)
 {
@@ -638,13 +643,7 @@
 	{ /* END */},
 }};
 
-__attribute__((constructor))
-static void __queue_init(void)
-{
-	tcp_req_cont_keywords_register(&tcp_cont_kws);
-	http_req_keywords_register(&http_req_kws);
-	sample_register_fetches(&smp_kws);
-}
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
 
 /*
  * Local variables:
diff --git a/src/sample.c b/src/sample.c
index 8ca4540..134ff76 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -21,6 +21,7 @@
 #include <common/chunk.h>
 #include <common/hash.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/standard.h>
 #include <common/uri_auth.h>
 #include <common/base64.h>
@@ -3089,6 +3090,8 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
 #ifdef DEBUG_EXPR
@@ -3139,10 +3142,4 @@
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
-__attribute__((constructor))
-static void __sample_init(void)
-{
-	/* register sample fetch and format conversion keywords */
-	sample_register_fetches(&smp_kws);
-	sample_register_convs(&sample_conv_kws);
-}
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
diff --git a/src/server.c b/src/server.c
index 0cf5eca..eb2bc6e 100644
--- a/src/server.c
+++ b/src/server.c
@@ -19,6 +19,7 @@
 #include <common/cfgparse.h>
 #include <common/config.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/namespace.h>
 #include <common/time.h>
 
@@ -1221,11 +1222,7 @@
 	{ NULL, NULL, 0 },
 }};
 
-__attribute__((constructor))
-static void __listener_init(void)
-{
-	srv_register_keywords(&srv_kws);
-}
+INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
 
 /* Recomputes the server's eweight based on its state, uweight, the current time,
  * and the proxy's algorihtm. To be used after updating sv->uweight. The warmup
@@ -4700,11 +4697,7 @@
 	{{},}
 }};
 
-__attribute__((constructor))
-static void __server_init(void)
-{
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 /*
  * This function applies server's status changes, it is
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 4fb984f..174ed1f 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -69,6 +69,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <common/standard.h>
 #include <common/ticks.h>
 #include <common/time.h>
@@ -8927,6 +8928,7 @@
 	{ { NULL }, NULL, NULL, NULL }
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
@@ -9010,6 +9012,8 @@
 	{ NULL, NULL, 0, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
  */
@@ -9019,6 +9023,8 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted, doing so helps
  * all code contributors.
@@ -9045,6 +9051,8 @@
 	{ NULL, NULL, 0 },
 };
 
+/* no initcall for ssl_bind_kws, these ones are parsed in the parser loop */
+
 static struct bind_kw_list bind_kws = { "SSL", { }, {
 	{ "allow-0rtt",            bind_parse_allow_0rtt,         0 }, /* Allow 0RTT */
 	{ "alpn",                  bind_parse_alpn,               1 }, /* set ALPN supported protocols */
@@ -9086,6 +9094,8 @@
 	{ NULL, NULL, 0 },
 }};
 
+INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted, doing so helps
  * all code contributors.
@@ -9135,6 +9145,8 @@
 	{ NULL, NULL, 0, 0 },
 }};
 
+INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
+
 static struct cfg_kw_list cfg_kws = {ILH, {
 	{ CFG_GLOBAL, "ca-base",  ssl_parse_global_ca_crt_base },
 	{ CFG_GLOBAL, "crt-base", ssl_parse_global_ca_crt_base },
@@ -9166,6 +9178,8 @@
 	{ 0, NULL, NULL },
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 /* transport-layer operations for SSL sockets */
 static struct xprt_ops ssl_sock = {
 	.snd_buf  = ssl_sock_from_buf,
@@ -9217,6 +9231,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
+
 #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
 
 static void ssl_sock_sctl_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
@@ -9265,12 +9281,6 @@
 	ssl_app_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
 	ssl_capture_ptr_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_capture_free_func);
 	ssl_pkey_info_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
-	sample_register_fetches(&sample_fetch_keywords);
-	acl_register_keywords(&acl_kws);
-	bind_register_keywords(&bind_kws);
-	srv_register_keywords(&srv_kws);
-	cfg_register_keywords(&cfg_kws);
-	cli_register_kw(&cli_kws);
 #ifndef OPENSSL_NO_ENGINE
 	ENGINE_load_builtin_engines();
 	hap_register_post_check(ssl_check_async_engine_count);
@@ -9330,8 +9340,6 @@
 #endif
 	/* Load SSL string for the verbose & debug mode. */
 	ERR_load_SSL_strings();
-
-	http_req_keywords_register(&http_req_actions);
 }
 
 #ifndef OPENSSL_NO_ENGINE
diff --git a/src/stats.c b/src/stats.c
index 9b0800e..d0544a3 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -29,6 +29,7 @@
 #include <common/config.h>
 #include <common/debug.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -3965,6 +3966,8 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
+
 struct applet http_stats_applet = {
 	.obj_type = OBJ_TYPE_APPLET,
 	.name = "<STATS>", /* used for logging */
@@ -3972,12 +3975,6 @@
 	.release = NULL,
 };
 
-__attribute__((constructor))
-static void __stat_init(void)
-{
-	cli_register_kw(&cli_kws);
-}
-
 /*
  * Local variables:
  *  c-indent-level: 8
diff --git a/src/stick_table.c b/src/stick_table.c
index 6bddc90..e24ef65 100644
--- a/src/stick_table.c
+++ b/src/stick_table.c
@@ -15,6 +15,7 @@
 #include <errno.h>
 
 #include <common/config.h>
+#include <common/initcall.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -3626,6 +3627,7 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 
 static struct action_kw_list tcp_conn_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
@@ -3634,6 +3636,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_conn_kws);
+
 static struct action_kw_list tcp_sess_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
 	{ "sc-inc-gpc1", parse_inc_gpc1, 1 },
@@ -3641,6 +3645,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_sess_kws);
+
 static struct action_kw_list tcp_req_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
 	{ "sc-inc-gpc1", parse_inc_gpc1, 1 },
@@ -3648,6 +3654,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_kws);
+
 static struct action_kw_list tcp_res_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
 	{ "sc-inc-gpc1", parse_inc_gpc1, 1 },
@@ -3655,6 +3663,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
+
 static struct action_kw_list http_req_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
 	{ "sc-inc-gpc1", parse_inc_gpc1, 1 },
@@ -3662,6 +3672,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
+
 static struct action_kw_list http_res_kws = { { }, {
 	{ "sc-inc-gpc0", parse_inc_gpc0, 1 },
 	{ "sc-inc-gpc1", parse_inc_gpc1, 1 },
@@ -3669,6 +3681,8 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
+
 ///* Note: must not be declared <const> as its list will be overwritten.
 // * Please take care of keeping this list alphabetically sorted.
 // */
@@ -3805,6 +3819,7 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &smp_fetch_keywords);
 
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
@@ -3832,19 +3847,4 @@
 	{ /* END */ },
 }};
 
-__attribute__((constructor))
-static void __stick_table_init(void)
-{
-	/* register som action keywords. */
-	tcp_req_conn_keywords_register(&tcp_conn_kws);
-	tcp_req_sess_keywords_register(&tcp_sess_kws);
-	tcp_req_cont_keywords_register(&tcp_req_kws);
-	tcp_res_cont_keywords_register(&tcp_res_kws);
-	http_req_keywords_register(&http_req_kws);
-	http_res_keywords_register(&http_res_kws);
-
-	/* register sample fetch and format conversion keywords */
-	sample_register_fetches(&smp_fetch_keywords);
-	sample_register_convs(&sample_conv_kws);
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
diff --git a/src/stream.c b/src/stream.c
index eda2aed..31146d2 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -18,8 +18,9 @@
 #include <common/config.h>
 #include <common/buffer.h>
 #include <common/debug.h>
-#include <common/memory.h>
 #include <common/hathreads.h>
+#include <common/initcall.h>
+#include <common/memory.h>
 
 #include <types/applet.h>
 #include <types/capture.h>
@@ -3411,24 +3412,22 @@
 	{{},}
 }};
 
+INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
+
 /* main configuration keyword registration. */
 static struct action_kw_list stream_tcp_keywords = { ILH, {
 	{ "use-service", stream_parse_use_service },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &stream_tcp_keywords);
+
 static struct action_kw_list stream_http_keywords = { ILH, {
 	{ "use-service", stream_parse_use_service },
 	{ /* END */ }
 }};
 
-__attribute__((constructor))
-static void __stream_init(void)
-{
-	tcp_req_cont_keywords_register(&stream_tcp_keywords);
-	http_req_keywords_register(&stream_http_keywords);
-	cli_register_kw(&cli_kws);
-}
+INITCALL1(STG_REGISTER, http_req_keywords_register, &stream_http_keywords);
 
 /*
  * Local variables:
diff --git a/src/tcp_rules.c b/src/tcp_rules.c
index 564b1ea..602749c 100644
--- a/src/tcp_rules.c
+++ b/src/tcp_rules.c
@@ -13,6 +13,7 @@
 #include <common/compat.h>
 #include <common/config.h>
 #include <common/debug.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <common/ticks.h>
@@ -1191,12 +1192,7 @@
 	{ 0, NULL, NULL },
 }};
 
-
-__attribute__((constructor))
-static void __tcp_protocol_init(void)
-{
-	cfg_register_keywords(&cfg_kws);
-}
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
 
 /*
  * Local variables:
diff --git a/src/vars.c b/src/vars.c
index 8f757f9..e44a786 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -2,6 +2,7 @@
 
 #include <common/cfgparse.h>
 #include <common/http.h>
+#include <common/initcall.h>
 #include <common/mini-clist.h>
 
 #include <types/vars.h>
@@ -861,42 +862,56 @@
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
+
 static struct sample_conv_kw_list sample_conv_kws = {ILH, {
 	{ "set-var",   smp_conv_store, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
 	{ "unset-var", smp_conv_clear, ARG1(1,STR), conv_check_var, SMP_T_ANY, SMP_T_ANY },
 	{ /* END */ },
 }};
 
+INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
+
 static struct action_kw_list tcp_req_sess_kws = { { }, {
 	{ "set-var",   parse_store, 1 },
 	{ "unset-var", parse_store, 1 },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_kws);
+
 static struct action_kw_list tcp_req_cont_kws = { { }, {
 	{ "set-var",   parse_store, 1 },
 	{ "unset-var", parse_store, 1 },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_kws);
+
 static struct action_kw_list tcp_res_kws = { { }, {
 	{ "set-var",   parse_store, 1 },
 	{ "unset-var", parse_store, 1 },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_kws);
+
 static struct action_kw_list http_req_kws = { { }, {
 	{ "set-var",   parse_store, 1 },
 	{ "unset-var", parse_store, 1 },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_kws);
+
 static struct action_kw_list http_res_kws = { { }, {
 	{ "set-var",   parse_store, 1 },
 	{ "unset-var", parse_store, 1 },
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_kws);
+
 static struct cfg_kw_list cfg_kws = {{ },{
 	{ CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global },
 	{ CFG_GLOBAL, "tune.vars.proc-max-size",   vars_max_size_proc   },
@@ -906,19 +921,12 @@
 	{ /* END */ }
 }};
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
 __attribute__((constructor))
 static void __vars_init(void)
 {
 	var_pool = create_pool("vars", sizeof(struct var), MEM_F_SHARED);
 
-	sample_register_fetches(&sample_fetch_keywords);
-	sample_register_convs(&sample_conv_kws);
-	tcp_req_sess_keywords_register(&tcp_req_sess_kws);
-	tcp_req_cont_keywords_register(&tcp_req_cont_kws);
-	tcp_res_cont_keywords_register(&tcp_res_kws);
-	http_req_keywords_register(&http_req_kws);
-	http_res_keywords_register(&http_res_kws);
-	cfg_register_keywords(&cfg_kws);
-
 	HA_RWLOCK_INIT(&var_names_rwlock);
 }
diff --git a/src/wurfl.c b/src/wurfl.c
index f7ac9b6..eb1fb47 100644
--- a/src/wurfl.c
+++ b/src/wurfl.c
@@ -5,6 +5,7 @@
 #include <common/chunk.h>
 #include <common/buffer.h>
 #include <common/errors.h>
+#include <common/initcall.h>
 #include <proto/arg.h>
 #include <proto/log.h>
 #include <proto/proto_http.h>
@@ -669,6 +670,8 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, cfg_register_keywords, &wurflcfg_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_fetch_kw_list fetch_kws = {ILH, {
 		{ "wurfl-get-all", ha_wurfl_get_all, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
@@ -677,19 +680,20 @@
 	}
 };
 
+INITCALL1(STG_REGISTER, sample_register_fetches, &fetch_kws);
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct sample_conv_kw_list conv_kws = {ILH, {
 		{ NULL, NULL, 0, 0, 0 },
 	}
 };
 
+INITCALL1(STG_REGISTER, sample_register_convs, &conv_kws);
+
 __attribute__((constructor))
 static void __wurfl_init(void)
 {
 	/* register sample fetch and format conversion keywords */
-	sample_register_fetches(&fetch_kws);
-	sample_register_convs(&conv_kws);
-	cfg_register_keywords(&wurflcfg_kws);
 	hap_register_build_opts("Built with WURFL support.", 0);
 	hap_register_post_check(ha_wurfl_init);
 	hap_register_post_deinit(ha_wurfl_deinit);