linker-table: add sections.h and port all code to v2 RFC linker table

This adds the sections.h file to allow easy association of
custom sections to standard ELF / Linux sections. It also
goes ahead and ports over all of the existing old .tbl
linker table code to the new linker table format. In order
to do this, we try to keep the code to match as much as
possible with the RFC v2 submission made [0]. Just for
references, you can review the discussion of the RFC v1
series as well [1].

Other relevant changes:

* It drops documentation in favor of that being done upstream,
  this removes the clutter while we just work on the proof
  of concept code. If this gets upstream then we'll just sync
  the tables.h from upstream to this tree. For now this is just
  a bit of a pain in the ass in between submissions.

* Extends pci.c with an example using LINKTABLE_FOR_EACH()
  and also LINKTABLE_RUN_ALL().

* Extends include/linux/kernel.h with things we need to make
  tables.h compile in userspace -- these are things we don't need.

Expected output:

$./main
Initializing x86 bare metal world
Number of init entries: 7
Initializing kasan ...
Early init for Kasan...
Completed initializing kasan !
Initializing memory ...
Completed initializing memory !
Initializing pci ...
PCI fixup size: 1
Demo: Using LINKTABLE_FOR_EACH
foo_fixup
Demo: Using LINKTABLE_RUN_ALL
foo_fixup
Completed initializing pci !
Initializing beta ...
Completed initializing beta !
Initializing alpha ...
Completed initializing alpha !
Initializing acme ...
Completed initializing acme !
Booting bare metal
Calling start_kernel()...
Running setup_arch for kasan ...
Calling setup_arch work for Kasan...

$ ./main -x
Initializing Xen guest
Number of init entries: 7
Initializing memory ...
Completed initializing memory !
Initializing pci ...
PCI fixup size: 1
Demo: Using LINKTABLE_FOR_EACH
foo_fixup
Demo: Using LINKTABLE_RUN_ALL
foo_fixup
Completed initializing pci !
Initializing xen_driver ...
Completed initializing xen_driver !
Booting a Xen guest
Calling start_kernel()..

[0] http://lkml.kernel.org/r/1455889559-9428-1-git-send-email-mcgrof@kernel.org
[1] http://1450217797-19295-1-git-send-email-mcgrof@do-not-panic.com

Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
diff --git a/Makefile b/Makefile
index 8e8ed3a..5970bd7 100644
--- a/Makefile
+++ b/Makefile
@@ -31,12 +31,9 @@
 # Simply placing alpha before beta will ensure
 # alpha runs prior to beta. This is expected given
 # SORT() for the init tables work on the order level
-# defined only, ie:
+# defined only:
 #
-#                 order level
-#                      |
-#                      V
-# *(SORT(.tbl.init_fns.*))
+# *(SORT(SECTION_TBL_ALL(SECTION_INIT_DATA)))
 #
 # The name of the struct places no effect to the actual linker order.
 OBJS =  arch/x86/kernel/sort-init.o \
diff --git a/arch/x86/include/asm/x86_init_fn.h b/arch/x86/include/asm/x86_init_fn.h
index 288189a..7f4cff4 100644
--- a/arch/x86/include/asm/x86_init_fn.h
+++ b/arch/x86/include/asm/x86_init_fn.h
@@ -128,11 +128,7 @@
 	INIT_DETECTED = BIT(1),
 };
 
-/* The x86 initialisation function table */
-#define X86_INIT_FNS __table(struct x86_init_fn, "x86_init_fns")
-
-/* Used to declares an x86 initialization table */
-#define __x86_init_fn(order_level) __table_entry(X86_INIT_FNS, order_level)
+DECLARE_LINKTABLE_INIT_DATA(struct x86_init_fn, x86_init_fns);
 
 /* Init order levels, we can start at 01 but reserve 01-09 for now */
 #define X86_INIT_ORDER_EARLY	10
@@ -147,7 +143,8 @@
 		 __early_init,						\
 		 __setup_arch,						\
 		 __late_init)						\
-	struct x86_init_fn __x86_init_fn_##__name __x86_init_fn(__level) = { \
+	static LINKTABLE_INIT_DATA(x86_init_fns, __level)		\
+	__x86_init_fn_##__early_init = {				\
 		.order_level = __level,					\
 		.supp_hardware_subarch = __supp_hardware_subarch,	\
 		.detect = __detect,					\
@@ -235,7 +232,6 @@
 void x86_init_fn_setup_arch(void);
 void x86_init_fn_late_init(void);
 
-void x86_init_fn_sort(struct x86_init_fn *start, struct x86_init_fn *finish);
-void x86_init_fn_check(struct x86_init_fn *start, struct x86_init_fn *finish);
+void x86_init_fn_init_tables(void);
 
 #endif /* __X86_INIT_TABLES_H */
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 1589be4..a3eb8de 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -7,8 +7,6 @@
 #include <linux/start_kernel.h>
 #include <linux/kasan.h>
 
-extern struct x86_init_fn __tbl_x86_start_init_fns[], __tbl_x86_end_init_fns[];
-
 void x86_64_start_reservations(void)
 {
 	switch (boot_params.hdr.hardware_subarch) {
@@ -37,9 +35,7 @@
 
 static void x86_64_start_kernel(void)
 {
-	x86_init_fn_sort(__tbl_x86_start_init_fns, __tbl_x86_end_init_fns);
-	x86_init_fn_check(__tbl_x86_start_init_fns, __tbl_x86_end_init_fns);
-
+	x86_init_fn_init_tables();
 	x86_init_fn_early_init();
 
 	x86_64_start_reservations();
diff --git a/arch/x86/kernel/init.c b/arch/x86/kernel/init.c
index a2273f0..af58cfe 100644
--- a/arch/x86/kernel/init.c
+++ b/arch/x86/kernel/init.c
@@ -6,6 +6,8 @@
 #include <asm/boot.h>
 #include <asm/setup.h>
 
+DEFINE_LINKTABLE_INIT_DATA(struct x86_init_fn, x86_init_fns);
+
 static bool x86_init_fn_supports_subarch(struct x86_init_fn *fn)
 {
 	if (!fn->supp_hardware_subarch) {
@@ -22,11 +24,11 @@
 	int ret;
 	struct x86_init_fn *init_fn;
 
-	unsigned int num_inits = table_num_entries(X86_INIT_FNS);
+	unsigned int num_inits = LINKTABLE_SIZE(x86_init_fns);
 
 	pr_info("Number of init entries: %d\n", num_inits);
 
-	for_each_table_entry(init_fn, X86_INIT_FNS) {
+	LINKTABLE_FOR_EACH(init_fn, x86_init_fns) {
 		if (!x86_init_fn_supports_subarch(init_fn))
 			continue;
 		if (!init_fn->detect)
@@ -52,7 +54,7 @@
 {
 	struct x86_init_fn *init_fn;
 
-	for_each_table_entry(init_fn, X86_INIT_FNS) {
+	LINKTABLE_FOR_EACH(init_fn, x86_init_fns) {
 		if ((init_fn->flags & INIT_DETECTED) && init_fn->late_init) {
 			pr_info("Running late init for %s ...\n", init_fn->name);
 			init_fn->late_init();
@@ -65,7 +67,7 @@
 {
 	struct x86_init_fn *init_fn;
 
-	for_each_table_entry(init_fn, X86_INIT_FNS) {
+	LINKTABLE_FOR_EACH(init_fn, x86_init_fns) {
 		if ((init_fn->flags & INIT_DETECTED) && init_fn->setup_arch) {
 			pr_info("Running setup_arch for %s ...\n", init_fn->name);
 			init_fn->setup_arch();
diff --git a/arch/x86/kernel/sort-init.c b/arch/x86/kernel/sort-init.c
index 369ab2b..6b0e907 100644
--- a/arch/x86/kernel/sort-init.c
+++ b/arch/x86/kernel/sort-init.c
@@ -19,16 +19,17 @@
 	return NULL;
 }
 
-
-void x86_init_fn_sort(struct x86_init_fn *start,
-		      struct x86_init_fn *finish) {
+static void x86_init_fn_sort(struct x86_init_fn *start,
+			     struct x86_init_fn *finish)
+{
 
 	struct x86_init_fn *p, *q, tmp;
 
 	for (p = start; p < finish; p++) {
 again:
 		q = x86_init_fn_find_dep(start, finish, p);
-		/* We are bit sneaky here. We use the memory address to figure
+		/*
+		 * We are bit sneaky here. We use the memory address to figure
 		 * out if the node we depend on is past our point, if so, swap.
 		 */
 		if (q > p) {
@@ -41,8 +42,8 @@
 
 }
 
-#ifdef DEBUG
-void x86_init_fn_check(struct x86_init_fn *start, struct x86_init_fn *finish)
+static void x86_init_fn_check(struct x86_init_fn *start,
+			      struct x86_init_fn *finish)
 {
 	struct x86_init_fn *p, *q, *x;
 
@@ -77,11 +78,11 @@
 		 * Be pedantic and do a full search on the entire table,
 		 * if we need further validation, after this is called
 		 * one could use an optimized version which just searches
-		 * on x86_find_dependents_of(p, finish, p), as we would have
+		 * on x86_init_fn_find_dep(p, finish, p), as we would have
 		 * guarantee on proper ordering both at the dependency level
 		 * and by order level.
 		 */
-		q = x86_find_dependents_of(start, finish, p);
+		q = x86_init_fn_find_dep(start, finish, p);
 		if (q && q > p) {
 			pr_info("EXECUTION ORDER INVALID! %s should be called before %s!\n",
 			       p->name, q->name);
@@ -98,9 +99,16 @@
 		}
 	}
 }
-#else
-inline void x86_init_fn_check(struct x86_init_fn *start,
-			      struct x86_init_fn *finish)
+
+void __ref x86_init_fn_init_tables(void)
 {
+	unsigned int num_inits = LINKTABLE_SIZE(x86_init_fns);
+
+	if (!num_inits)
+		return;
+
+	x86_init_fn_sort(LINKTABLE_START(x86_init_fns),
+			 LINKTABLE_END(x86_init_fns));
+	x86_init_fn_check(LINKTABLE_START(x86_init_fns),
+			  LINKTABLE_END(x86_init_fns));
 }
-#endif
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index cbbae39..adebf1e 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -3,6 +3,9 @@
    Copying and distribution of this script, with or without modification,
    are permitted in any medium without royalty provided the copyright
    notice and this notice are preserved.  */
+
+#include <linux/sections.h>
+
 OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
 	      "elf64-x86-64")
 OUTPUT_ARCH(i386:x86-64)
@@ -58,6 +61,9 @@
     *(.text.exit .text.exit.*)
     *(.text.startup .text.startup.*)
     *(.text.hot .text.hot.*)
+    *(SORT(SECTION_TBL_ALL(SECTION_TEXT)))
+    *(SORT(SECTION_TBL_ALL(SECTION_INIT)))
+    *(SORT(SECTION_TBL_ALL(SECTION_INIT_CALL)))
     *(.text .stub .text.* .gnu.linkonce.t.*)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
@@ -69,7 +75,14 @@
   PROVIDE (__etext = .);
   PROVIDE (_etext = .);
   PROVIDE (etext = .);
-  .rodata         : { *(.rodata) *(SORT(.rodata.*)) *(.gnu.linkonce.r.*) }
+  .rodata         :
+  {
+	*(.rodata)
+	*(SORT(.rodata.*))
+	*(SORT(SECTION_TBL_ALL(SECTION_RODATA)))
+	*(SORT(SECTION_TBL_ALL(SECTION_INIT_RODATA)))
+	*(.gnu.linkonce.r.*)
+  }
   .rodata1        : { *(.rodata1) }
   .eh_frame_hdr : { *(.eh_frame_hdr) }
   .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
@@ -146,38 +159,14 @@
   .data           :
   {
     *(.data .data.* .gnu.linkonce.d.*)
+    *(SORT(SECTION_TBL_ALL(SECTION_DATA)))
+    *(SORT(SECTION_TBL_ALL(SECTION_INIT_DATA)))
     SORT(CONSTRUCTORS)
   }
   .data1          : { *(.data1) }
   _edata = .; PROVIDE (edata = .);
   . = .;
 
-  .tbl            : {
-
-	/*
-	 * x86 generic init solution: this will sort all order levels
-	 * lexicographically. Something like SORT_BY_INIT_PRIORITY()
-	 * which sorts specifically on numeric order is desirable but
-	 * that would impose a change on binutils to generalize
-	 * SORT_BY_INIT_PRIORITY() for any section, SORT_BY_INIT_PRIORITY()
-	 * is specific to the init sections, and that would also mean having
-	 * a bump on requirments for building Linux. Using SORT() should
-	 * suffice, * its what gpxe uses. For things in the same order
-	 * level we rely on order in the C file, and also order on the
-	 * Makefile. Since this solution also embraces the IOMMU init solution
-	 * it has further sorting semantics implemented in C and its semantics
-	 * are defined in x86_init_fn.h and implemented in sort-init.c.
-	 */
-	__tbl_x86_start_init_fns = .;
-	*(SORT(.tbl.x86_init_fns.*))
-	__tbl_x86_end_init_fns = .;
-
-	/* ... etc ... */
-
-	/* You would add other tables here as needed */
-  }
-  . = ALIGN(8);
-
   __bss_start = .;
   .bss            :
   {
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index c91fdeb..4b0e1be 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1,6 +1,15 @@
 #include <stdio.h>
 #include <unistd.h>
 
+/* Not everyone customizes this so leave it as-is for userspace */
+#define VMLINUX_SYMBOL(x) x
+
+/* This is for ancient compilers */
+#define LTO_REFERENCE_INITCALL(x)
+
+/* no equivalent on userspace yet */
+#define __ref
+
 #define BIT(nr)		(1UL << (nr))
 
 #define pr_info(fmt, ...) printf(fmt, ##__VA_ARGS__)
diff --git a/include/linux/sections.h b/include/linux/sections.h
new file mode 100644
index 0000000..d6f7a30
--- /dev/null
+++ b/include/linux/sections.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_SECTIONS_H
+#define _LINUX_SECTIONS_H
+
+#define SECTION_RODATA			.rodata
+#define SECTION_DATA			.data
+#define SECTION_TEXT			.text
+#define SECTION_INIT			.init.text
+#define SECTION_INIT_DATA		.init.data
+#define SECTION_INIT_RODATA		.init.rodata
+#define SECTION_INIT_CALL		.initcall
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Without this you end up with the section macro
+ * as part of the name
+ */
+#define __SECTION_TBL(section, name, level)				\
+	#section ".tbl." #name "." #level
+
+#define SECTION_TBL(section, name, level)				\
+	__SECTION_TBL(section, name, level)
+
+#endif
+
+/* For use on linker scripts and helpers */
+#define ___SECTION_TBL(section, name)					\
+	section##.tbl.##name
+
+/* glob to capture all linker table uses for this section */
+#define SECTION_TBL_ALL(section)					\
+	___SECTION_TBL(section,*)
+
+#endif /* _LINUX_SECTIONS_H */
diff --git a/include/linux/tables.h b/include/linux/tables.h
index c6650a0..45857f0 100644
--- a/include/linux/tables.h
+++ b/include/linux/tables.h
@@ -1,179 +1,162 @@
-#ifndef _LINUX_TABLES_H
-#define _LINUX_TABLES_H
+#ifndef _LINUX_LINKER_TABLES_H
+#define _LINUX_LINKER_TABLES_H
 
-/**
- * DOC: linker tables - for when #ifdefs are harmful
+#include <linux/sections.h>
+
+/*
+ * Linux linker tables
  *
- * Overuse of C #ifdefs can be problematic for certain types of code.  Linux
- * provides a rich array of features, but all these features take up valuable
- * space in a kernel image. The traditional solution to this problem has been
- * for each feature to have its own Kconfig entry and for the respective code
- * to be wrapped around #ifdefs, allowing the feature to be compiled in only
- * if desired.
+ * Copyright (C) 2005-2009 Michael Brown <mcb30@ipxe.org>
+ * Copyright (C) 2015-2016 Luis R. Rodriguez <mcgrof@kernel.org>
  *
- * The problem with this is that over time it becomes very difficult and time
- * consuming to compile, let alone test, all possible versions of Linux. Code
- * that is not typically used tends to suffer from bit-rot over time. It can
- * become difficult to predict which combinations of compile-time options will
- * result in code that can compile and link correctly.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * To solve this problem linker tables can be used on Linux, it enables you to
- * always force compiling of features that one wishes to avoid bit-rot by while
- * still enabling you to disable linking the feature code into the final kernel
- * image if the features have been disabled via Kconfig. The code is derivative
- * of gPXE table's solution embraced on gPXE >= 5 and can optionally be used in
- * conjunction with Linux's own custom init dependency solution, originally
- * developed for use in IOMMU. For more details on history and to see how this
- * code evolved refer to the userspace mockup solution on github [0]. To allow
- * for easy testing of extensions that code can be used and extended prior to
- * inclusion in Linux. Contrary to gPXE's solution which stives to force
- * compilation of *everything* Linux's solution allows for developers to be
- * selective over where one should use linker tables.
- *
- * [0] https://github.com/mcgrof/table-init/
- *
- * To use linker tables, features should be implemented in separate C files,
- * and should always be compiled -- they should not be guarded with a C code
- * #ifdef CONFIG_FOO statements. By making code always compile, you avoid
- * the problem of bit-rot in rarely-used code.
- *
- * For instance, let's assume we want to always force compilation of both FOO
- * and BAR code in the kernel but avoid linking it.  When you enable the
- * features via Kconfig you'd end up with:
- *
- *   #define CONFIG_FOO 1
- *
- * You typically would then just use this on your Makefile to selectively
- * compile and link the features:
- *
- * obj-$(CONFIG_FOO) += foo.o
- *
- * If using linker tables you'd instead use:
- *
- * XXX: is this true?
- * obj-y += foo.o
- *
- * The reason why this works is due to the magic behind linker tables.
- * Traditionally, we would implement integration of these features
- * through C code as follows:
- *
- *	foo_init();
- *
- * You'd then have a foo.h which would have:
- *
- *  #ifdef CONFIG_FOO
- *  void foo(void);
- *  #else
- *  static inline void foo(void) { }
- *  #endif
- *
- * With linker tables this is no longer necessary as your init routines would
- * be implicit, you'd instead call:
- *
- *	call_init_fns();
- *
- * call_init_fns() would call all functions present in this init table and if
- * and only if foo.o gets linked in, then its initialisation function will be
- * called.
- *
- * The linker script takes care of assembling the tables for us. All of our
- * table sections have names of the format .tbl.NAME.NN. NAME designates the
- * data structure stored in the table. For instance if you had defined a
- * struct init_fn to data type your init sequences you would have a respective
- * init_fns table name declared as reference for these init sequences. NN is a
- * two-digit decimal number used to impose an "order level" upon the tables if
- * required. NN=00 is reserved for the symbol indicating "table start", and
- * NN=99 is reserved for the symbol indicating "table end". In order for the
- * call_init_fns() to work behind the scenes the custom linker script would
- * need to define the beginning of the table, the end of the table, and in
- * between it should use SORT() to give order-level effect. To account for
- * all of your struct init_fn init sequences, in your linker script you would
- * have:
- *
- *   .tbl            : {
- *	__tbl_start_init_fns = .;
- * 	*(SORT(.tbl.init_fns.*))
- *	__tbl_end_init_fns = .;
- *
- *	Other init tables can go here as well for different
- *	structures.
- *   }
- *
- * The order-level is really only a helper, if only one order level is
- * used, the next contributing factor to order is the order of the code
- * in the C file, and the order of the objects in the Makefile. Using
- * an order level then should not really be needed in most cases, its
- * use however enables to compartamentalize code into tables where ordering
- * through C file or through the Makefile would otherwise be very difficult.
- *
- * As an example, suppose that we want to create a "frobnicator"
- * feature framework, and allow for several independent modules to
- * provide frobnicating services. Then we would create a frob.h
- * header file containing e.g.
- *
- *   struct frobnicator {
- *      const char *name;
- *	void (*frob) (void);
- *   };
- *
- *   #define FROBNICATORS __table (struct frobnicator, "frobnicators")
- *   #define __frobnicator __table_entry (FROBNICATORS, 01)
- *
- * Any module providing frobnicating services would look something
- * like
- *
- *   #include "frob.h"
- *
- *   static void my_frob (void) {
- *	... Do my frobnicating
- *   }
- *
- *   struct frob my_frobnicator __frobnicator = {
- *	.name = "my_frob",
- *	.frob = my_frob,
- *   };
- *
- * The central frobnicator code (frob.c) would use the frobnicating
- * modules as follows
- *
- *   #include "frob.h"
- *
- *   void frob_all(void) {
- *	struct frob *frob;
- *
- *	for_each_table(frob, FROBNICATORS) {
- *         pr_info("Calling frobnicator \"%s\"\n", frob->name);
- *	   frob->frob();
- *	}
- *   }
+ * Due to this file being licensed under the GPL there is controversy over
+ * whether this permits you to write a module that #includes this file
+ * without placing your module under the GPL.  Please consult a lawyer for
+ * advice before doing this.
  */
 
+/* This is a trimmed version with no documentation */
+
+#define LINKTABLE_ALIGNMENT(name)	__alignof__(__typeof__(name[0]))
+#define LINKTABLE_SIZE(name)	((name##__end) - (name))
+#define LINKTABLE_EMPTY(name)	(LINKTABLE_SIZE(name) == 0)
+#define LINKTABLE_START(tbl)	tbl
+#define LINKTABLE_END(tbl)	tbl##__end
+
+#define LINKTABLE_ADDR_WITHIN(tbl, addr)				\
+	 (addr >= (unsigned long) LINKTABLE_START(tbl) &&		\
+          addr < (unsigned long) LINKTABLE_END(tbl))
+
+#define LINKTABLE_DATA_WEAK(name, level)				\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     weak,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_DATA, name, level))))
+
+#define LINKTABLE_TEXT_WEAK(name, level)				\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     weak,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_TEXT, name, level))))
+
+
+#define LINKTABLE_RO_WEAK(name, level)					\
+	const __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     weak,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_RODATA, name, level))))
+
+#define LINKTABLE_INIT_WEAK(name, level)					\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     weak,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_INIT, name, level))))
+
+#define LINKTABLE_INIT_DATA_WEAK(name, level)				\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     weak,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_INIT_DATA, name, level))))
+
+#define LINKTABLE_TEXT(name, level)					\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_TEXT, name, level))))
+
+#define LINKTABLE_DATA(name, level)					\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_DATA, name, level))))
+#define LINKTABLE_RO(name, level)					\
+	const __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_RODATA, name, level))))
+
+#define LINKTABLE_INIT(name, level)					\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_INIT, name, level))))
+#define LINKTABLE_INIT_DATA(name, level)					\
+	      __typeof__(name[0])					\
+	      __attribute__((used,					\
+			     __aligned__(LINKTABLE_ALIGNMENT(name)),	\
+			     section(SECTION_TBL(SECTION_INIT_DATA, name, level))))
+
+#define DECLARE_LINKTABLE_TEXT(type, name)				\
+	 extern type name[], name##__end[];
+
+#define DECLARE_LINKTABLE_DATA(type, name)				\
+	 extern type name[], name##__end[];
+
 #define DECLARE_LINKTABLE_RO(type, name)				\
 	 extern const type name[], name##__end[];
 
+#define DECLARE_LINKTABLE_INIT(type, name)				\
+	 extern type name[], name##__end[];
+
+#define DECLARE_LINKTABLE_INIT_DATA(type, name)				\
+	 extern type name[], name##__end[];
+
+
+#define DEFINE_LINKTABLE_TEXT(type, name)				\
+	DECLARE_LINKTABLE_TEXT(type, name);				\
+	LINKTABLE_TEXT_WEAK(name, ) VMLINUX_SYMBOL(name)[0] = {};	\
+	LTO_REFERENCE_INITCALL(name);					\
+	LINKTABLE_TEXT(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {};\
+	LTO_REFERENCE_INITCALL(name##__end);
+
+#define DEFINE_LINKTABLE_DATA(type, name)				\
+	DECLARE_LINKTABLE_DATA(type, name);				\
+	LINKTABLE_DATA_WEAK(name, ) VMLINUX_SYMBOL(name)[0] = {};	\
+	LTO_REFERENCE_INITCALL(name);					\
+	LINKTABLE_DATA(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {};\
+	LTO_REFERENCE_INITCALL(name##__end);
+
 #define DEFINE_LINKTABLE_RO(type, name)					\
 	DECLARE_LINKTABLE_RO(type, name);				\
-	const type __attribute__((used,					\
-				  section(".rodata.tbl."		\
-					  #name ".")))			\
-				name[0] = {};				\
-	const type __attribute__((used,					\
-				  section(".rodata.tbl."		\
-					  #name ".~")))			\
-				name##__end[0] = {};
+	LINKTABLE_RO_WEAK(name, ) VMLINUX_SYMBOL(name)[0] = {};		\
+	LTO_REFERENCE_INITCALL(name);					\
+	LINKTABLE_RO(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {};	\
+	LTO_REFERENCE_INITCALL(name##__end);
 
-#define LINKTABLE_RO(name, level)					\
-	static const __typeof__(name[0])					\
-		__attribute__((used, section(".rodata.tbl." 		\
-					     #name "." #level)))
+#define DEFINE_LINKTABLE_INIT(type, name)					\
+	DECLARE_LINKTABLE_INIT(type, name);					\
+	LINKTABLE_INIT_WEAK(name, ) VMLINUX_SYMBOL(name)[0] = {};		\
+	LTO_REFERENCE_INITCALL(name);						\
+	LINKTABLE_INIT(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {};	\
+	LTO_REFERENCE_INITCALL(name##__end);
 
-#define LINKTABLE_SIZE(name)	((name##__end) - (name))
+#define DEFINE_LINKTABLE_INIT_DATA(type, name)					\
+	DECLARE_LINKTABLE_INIT_DATA(type, name);					\
+	LINKTABLE_INIT_DATA_WEAK(name, ) VMLINUX_SYMBOL(name)[0] = {};		\
+	LTO_REFERENCE_INITCALL(name);						\
+	LINKTABLE_INIT_DATA(name, ~) VMLINUX_SYMBOL(name##__end)[0] = {};	\
+	LTO_REFERENCE_INITCALL(name##__end);
+
+#define LINKTABLE_FOR_EACH(pointer, tbl)				\
+	for (pointer = LINKTABLE_START(tbl);				\
+	     pointer < LINKTABLE_END(tbl);				\
+	     pointer++)
 
 #define LINKTABLE_RUN_ALL(tbl, func, args...)				\
 do {									\
 	size_t i;							\
 	for (i = 0; i < LINKTABLE_SIZE(tbl); i++)			\
-		(tbl[i]) func (args);					\
+		(tbl[i]).func (args);					\
 } while (0);
 
 #define LINKTABLE_RUN_ERR(tbl, func, args...)				\
@@ -181,255 +164,8 @@
 	size_t i;							\
 	int err = 0;							\
 	for (i = 0; !err && i < LINKTABLE_SIZE(tbl); i++)		\
-		err = (tbl[i]) func (args);				\
+		err = (tbl[i]).func (args);				\
 		err; \
 })
 
-#define LINKTABLE_FOR_EACH(pointer, tbl)				\
-	for (pointer = tbl;						\
-	     pointer < tbl##__end;					\
-	     pointer++)
-
-
-/*
- * __table - Declares a linker table
- *
- * @type: data type
- * @name: table name
- * 
- * Declares a linker table.
- */
-#define __table(type, name) (type, name)
-
-/*
- * __table_type() - get linker table data type
- *
- * @table: linker table
- *
- * Gives you the linker table data type.
- */
-#define __table_type(table) __table_extract_type table
-#define __table_extract_type(type, name) type
-
-/*
- * __table_name - get linker table name
- *
- * @table: linker table
- *
- * Gives you the table name.
- */
-#define __table_name(table) __table_extract_name table
-#define __table_extract_name(type, name) name
-
-/*
- * __table_section - get linker table section name
- *
- * @table: linker table
- * @idx: order level, this is the sub-table index
- *
- * Declares the section name.
- */
-#define __table_section(table, idx) \
-	".tbl." __table_name (table) "." __table_str (idx)
-#define __table_str(x) #x
-
-/*
- * __table_alignment - get linker table alignment
- *
- * @table: linker table
- *
- * Gives you the linker table alignment.
- */
-#define __table_alignment( table ) __alignof__ (__table_type(table))
-
-/*
- * __table_entry - declare a linker table entry
- *
- * @table: linker table
- * @idx: order level, the sub-table index
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table (struct frobnicator, "frobnicators")
- *   #define __frobnicator __table_entry(FROBNICATORS, 01)
- *
- *   struct frobnicator my_frob __frobnicator = {
- *      ...
- *   };
- */
-#define __table_entry(table, idx)					\
-	__attribute__ ((__section__(__table_section(table, idx)),	\
-			__aligned__(__table_alignment(table))))
-
-/*
- * __table_entries - get start of linker table entries
- *
- * @table: linker table
- * @idx: order level, the sub-table index
- *
- * This gives you the start of the respective linker table entries
- */
-#define __table_entries(table, idx) ( {					\
-	static __table_type(table) __table_entries[0]			\
-		__table_entry(table, idx); 				\
-	__table_entries; } )
-
-/*
- * table_start - get start of linker table
- *
- * @table: linker table
- *
- * This gives you the start of the respective linker table.
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table (struct frobnicator, "frobnicators")
- *
- *   struct frobnicator *frobs = table_start(FROBNICATORS);
- */
-#define table_start(table) __table_entries(table, 00)
-
-/*
- * table_end - get end of linker table
- *
- * @table: linker table
- *
- * This gives you the end of the respective linker table.
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table (struct frobnicator, "frobnicators")
- *
- *   struct frobnicator *frobs_end = table_end(FROBNICATORS);
- */
-#define table_end(table) __table_entries(table, 99)
-
-/*
- * table_num_entries - get number of entries in linker table
- *
- * @table: linker table
- *
- * This gives you the number of entries in linker table.
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table(struct frobnicator, "frobnicators")
- *
- *   unsigned int num_frobs = table_num_entries(FROBNICATORS);
- */
-#define table_num_entries(table)					\
-	((unsigned int) (table_end(table) -				\
-			 table_start(table)))
-
-/*
- * for_each_table_entry - iterate through all entries within a linker table
- *
- * @pointer: entry pointer
- * @table: linker table
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table(struct frobnicator, "frobnicators")
- *
- *   struct frobnicator *frob;
- *
- *   for_each_table_entry(frob, FROBNICATORS) {
- *     ...
- *   }
- */
-#define for_each_table_entry(pointer, table)				\
-	for (pointer = table_start(table);				\
-	     pointer < table_end(table);				\
-	     pointer++)
-
-/**
- * for_each_table_entry_reverse - iterate through linker table in reverse order
- *
- * @pointer: entry pointer
- * @table: linker table
- *
- * Example usage:
- *
- *   #define FROBNICATORS __table(struct frobnicator, "frobnicators")
- *
- *   struct frobnicator *frob;
- *
- *   for_each_table_entry_reverse(frob, FROBNICATORS) {
- *     ...
- *   }
- */
-#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 /* _LINUX_TABLES_H */
+#endif /* _LINUX_LINKER_TABLES_H */
diff --git a/pci.c b/pci.c
index f1d18a0..85c016c 100644
--- a/pci.c
+++ b/pci.c
@@ -9,10 +9,17 @@
 void early_init_pci(void) {
 
 	const struct pci_fixup *fixup;
+	unsigned int tbl_size =  LINKTABLE_SIZE(pci_fixup_early);
+
+	pr_info("PCI fixup size: %d\n", tbl_size);
 
 	sleep(1);
+	pr_info("Demo: Using LINKTABLE_FOR_EACH\n");
 	LINKTABLE_FOR_EACH(fixup, pci_fixup_early)
 		fixup->hook();
+
+	pr_info("Demo: Using LINKTABLE_RUN_ALL\n");
+	LINKTABLE_RUN_ALL(pci_fixup_early, hook,);
 }
 
 bool detect_pci(void) {
diff --git a/xen.c b/xen.c
index d857f7b..f5ccdcb 100644
--- a/xen.c
+++ b/xen.c
@@ -5,15 +5,11 @@
 #include <asm/x86_init_fn.h>
 #include <asm/x86.h>
 
-extern struct x86_init_fn __tbl_x86_start_init_fns[], __tbl_x86_end_init_fns[];
-
 void startup_xen(void)
 {
-	x86_init_fn_sort(__tbl_x86_start_init_fns, __tbl_x86_end_init_fns);
-	x86_init_fn_check(__tbl_x86_start_init_fns, __tbl_x86_end_init_fns);
-
 	pr_info("Initializing Xen guest\n");
 
+	x86_init_fn_init_tables();
 	x86_init_fn_early_init();
 
 	x86_64_start_reservations();