aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@kernel.org>2016-05-25 16:43:27 -0700
committerLuis R. Rodriguez <mcgrof@kernel.org>2016-06-23 15:23:28 -0700
commit75187b8895ebbe7d864d35d924572df875bea382 (patch)
tree28968c7783ef048e89d2c123f6033668052e3706
parent39173728ea2d352032bdc8fc17b453afd6a8375b (diff)
downloadlinker-tables-75187b8895ebbe7d864d35d924572df875bea382.tar.gz
tables.h: split off linker table in 3 parts
There are two ways custom ELF sections are used: a) text "ranges": Collection of executable routines, this use varies but one example is the kernel's kprobes. Since kprobes uses two custom sections, to be specific this references the use case for .kprobes.text -- these are currently rolled into the kernel's INIT_DATA in include/asm-generic/vmlinux.lds.h and used as INIT_DATA_SECTION(16) on x86 under arch/x86/kernel/vmlinux.lds.S b) tables: Custom data structures stitched together We split off linker tables into 3 sections: I. include/linux/sections.h II. include/linux/tables.h III. include/linux/ranges.h The sections.h already existed, we just keep stuffing in there generic helpers which allow us to streamlne customizing Linux sections. Motivation for this is as per hpa [0]: ----------------------------------------------------------------------- 1. priority ordering doesn't make any sense for ranges. 2. ranges can be hierarchial, that is, range "bar" can be entirely inside range "foo". 3. ranges aren't typed (although in C, that pretty much means they are "char" or "unsigned char" as there really isn't any way to define an "array of void".) 4. the only useful operator on a range is "is address X inside this range"; this operator is likely *not* useful for a table, since if you have to ever invoke it you are probably doing something very wrong. For this to work, we need strings such that they will always sort in the appropriate order with the bracket symbols around subranges. ----------------------------------------------------------------------- This is an initial attempt to provide support for this. We do this by first acknowledging that that both section ranges and linker tables need common building blocks, and then granting the option to declare either a section range, or letting you customize this further with a custom data structure. This at least addresses the conceptual division between section ranges and linker tables. No section range support test case is provided here, although upstream this would be used for the .kprobes.text. We'll next need to try to demo an example with subsections. [0] http://lkml.kernel.org/r/56CCE9B6.4080000@zytor.com Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
-rw-r--r--arch/x86/include/asm/x86_init_fn.h2
-rw-r--r--arch/x86/kernel/init.c2
-rw-r--r--arch/x86/kernel/sort-init.c10
-rw-r--r--include/linux/ranges.h14
-rw-r--r--include/linux/sections.h33
-rw-r--r--include/linux/tables.h58
-rw-r--r--pci.c4
7 files changed, 70 insertions, 53 deletions
diff --git a/arch/x86/include/asm/x86_init_fn.h b/arch/x86/include/asm/x86_init_fn.h
index 7f4cff4..9b739c1 100644
--- a/arch/x86/include/asm/x86_init_fn.h
+++ b/arch/x86/include/asm/x86_init_fn.h
@@ -128,7 +128,7 @@ enum x86_init_fn_flags {
INIT_DETECTED = BIT(1),
};
-DECLARE_LINKTABLE_INIT_DATA(struct x86_init_fn, x86_init_fns);
+DECLARE_LINKTABLE_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
diff --git a/arch/x86/kernel/init.c b/arch/x86/kernel/init.c
index af58cfe..f16f1d4 100644
--- a/arch/x86/kernel/init.c
+++ b/arch/x86/kernel/init.c
@@ -24,7 +24,7 @@ void x86_init_fn_early_init(void)
int ret;
struct x86_init_fn *init_fn;
- unsigned int num_inits = LINKTABLE_SIZE(x86_init_fns);
+ unsigned int num_inits = SECTION_RANGE_SIZE(x86_init_fns);
pr_info("Number of init entries: %d\n", num_inits);
diff --git a/arch/x86/kernel/sort-init.c b/arch/x86/kernel/sort-init.c
index 6b0e907..6a1f068 100644
--- a/arch/x86/kernel/sort-init.c
+++ b/arch/x86/kernel/sort-init.c
@@ -102,13 +102,13 @@ static void x86_init_fn_check(struct x86_init_fn *start,
void __ref x86_init_fn_init_tables(void)
{
- unsigned int num_inits = LINKTABLE_SIZE(x86_init_fns);
+ unsigned int num_inits = SECTION_RANGE_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));
+ x86_init_fn_sort(SECTION_RANGE_START(x86_init_fns),
+ SECTION_RANGE_END(x86_init_fns));
+ x86_init_fn_check(SECTION_RANGE_START(x86_init_fns),
+ SECTION_RANGE_END(x86_init_fns));
}
diff --git a/include/linux/ranges.h b/include/linux/ranges.h
new file mode 100644
index 0000000..d79690f
--- /dev/null
+++ b/include/linux/ranges.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_RANGES_H
+#define _LINUX_RANGES_H
+
+#include <linux/sections.h>
+
+/* Linker tables shalt not use this */
+#define SECTION_ADDR_IN_RANGE(name, addr) \
+ (addr >= (unsigned long) LINUX_SECTION_START(name) && \
+ addr < (unsigned long) LINUX_SECTION_END(name))
+
+#define DECLARE_SECTION_RANGE(name) \
+ DECLARE_LINUX_SECTION_RO(char, name)
+
+#endif /* _LINUX_RANGES_H */
diff --git a/include/linux/sections.h b/include/linux/sections.h
index cdcfd56..1604826 100644
--- a/include/linux/sections.h
+++ b/include/linux/sections.h
@@ -17,19 +17,38 @@
#ifndef __ASSEMBLY__
-/*
- * Without this you end up with the section macro
- * as part of the name
- */
+#define LINUX_SECTION_ALIGNMENT(name) __alignof__(__typeof__(name[0]))
+#define LINUX_SECTION_SIZE(name) ((name##__end) - (name))
+#define LINUX_SECTION_EMPTY(name) (LINUX_RANGE_SIZE(name) == 0)
+#define LINUX_SECTION_START(name) name
+#define LINUX_SECTION_END(name) name##__end
+
+#define LINUX_SECTION(name, section) \
+ #section "." #name
+
+#define DECLARE_LINUX_SECTION(type, name) \
+ extern type name[], name##__end[];
+
+#define DECLARE_LINUX_SECTION_RO(type, name) \
+ extern const type name[], name##__end[];
+
#define __SECTION_TBL(section, name, level) \
#section ".tbl." #name "." #level
-#define SECTION_TBL(section, name, level) \
+#define SECTION_TBL(section, name, level) \
__SECTION_TBL(section, name, level)
-#endif
+#endif /* __ASSEMBLY__ */
-/* For use on linker scripts and helpers */
+/*
+ * This section is for use on linker scripts and helpers
+ */
+
+/*
+ *
+ * Without this you end up with the section macro
+ * as part of the name
+ */
#define ___SECTION_TBL(section, name) \
section##.tbl.##name
diff --git a/include/linux/tables.h b/include/linux/tables.h
index f3db2c8..a984474 100644
--- a/include/linux/tables.h
+++ b/include/linux/tables.h
@@ -22,28 +22,22 @@
/* 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))
+ (addr >= (unsigned long) LINUX_SECTION_START(tbl) && \
+ addr < (unsigned long) LINUX_SECTION_END(tbl))
#define LINKTABLE_DATA_WEAK(name, level) \
__typeof__(name[0]) \
__attribute__((used, \
weak, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_DATA, name, level))))
#define LINKTABLE_WEAK(name, level) \
const __typeof__(name[0]) \
__attribute__((used, \
weak, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_TEXT, name, level))))
@@ -51,66 +45,56 @@
const __typeof__(name[0]) \
__attribute__((used, \
weak, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_RODATA, name, level))))
#define LINKTABLE_INIT_WEAK(name, level) \
const __typeof__(name[0]) \
__attribute__((used, \
weak, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_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)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_INIT_DATA, name, level))))
#define LINKTABLE(name, level) \
const __typeof__(name[0]) \
__attribute__((used, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_TEXT, name, level))))
#define LINKTABLE_DATA(name, level) \
__typeof__(name[0]) \
__attribute__((used, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_DATA, name, level))))
#define LINKTABLE_RO(name, level) \
const __typeof__(name[0]) \
__attribute__((used, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_RODATA, name, level))))
#define LINKTABLE_INIT(name, level) \
const __typeof__(name[0]) \
__attribute__((used, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_INIT, name, level))))
#define LINKTABLE_INIT_DATA(name, level) \
__typeof__(name[0]) \
__attribute__((used, \
- __aligned__(LINKTABLE_ALIGNMENT(name)), \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)), \
section(SECTION_TBL(SECTION_INIT_DATA, name, level))))
#define DECLARE_LINKTABLE(type, name) \
- extern const type name[], name##__end[];
+ DECLARE_LINUX_SECTION_RO(type, name)
#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 const type name[], name##__end[];
-
-#define DECLARE_LINKTABLE_INIT_DATA(type, name) \
- extern type name[], name##__end[];
-
+ DECLARE_LINUX_SECTION(type, name)
#define DEFINE_LINKTABLE(type, name) \
DECLARE_LINKTABLE(type, name); \
@@ -127,35 +111,35 @@
LTO_REFERENCE_INITCALL(name##__end);
#define DEFINE_LINKTABLE_RO(type, name) \
- DECLARE_LINKTABLE_RO(type, name); \
+ DECLARE_LINKTABLE(type, name); \
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 DEFINE_LINKTABLE_INIT(type, name) \
- DECLARE_LINKTABLE_INIT(type, name); \
+ DECLARE_LINKTABLE(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 DEFINE_LINKTABLE_INIT_DATA(type, name) \
- DECLARE_LINKTABLE_INIT_DATA(type, name); \
+ DECLARE_LINKTABLE_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); \
+ for (pointer = LINUX_SECTION_START(tbl); \
+ pointer < LINUX_SECTION_END(tbl); \
pointer++)
#define LINKTABLE_RUN_ALL(tbl, func, args...) \
do { \
size_t i; \
- for (i = 0; i < LINKTABLE_SIZE(tbl); i++) \
+ for (i = 0; i < LINUX_SECTION_SIZE(tbl); i++) \
(tbl[i]).func (args); \
} while (0);
@@ -163,7 +147,7 @@ do { \
({ \
size_t i; \
int err = 0; \
- for (i = 0; !err && i < LINKTABLE_SIZE(tbl); i++) \
+ for (i = 0; !err && i < LINUX_SECTION_SIZE(tbl); i++) \
err = (tbl[i]).func (args); \
err; \
})
diff --git a/pci.c b/pci.c
index 85c016c..0279a32 100644
--- a/pci.c
+++ b/pci.c
@@ -4,12 +4,12 @@
#include <linux/pci.h>
-DECLARE_LINKTABLE_RO(struct pci_fixup, pci_fixup_early);
+DECLARE_LINKTABLE(struct pci_fixup, pci_fixup_early);
void early_init_pci(void) {
const struct pci_fixup *fixup;
- unsigned int tbl_size = LINKTABLE_SIZE(pci_fixup_early);
+ unsigned int tbl_size = LINUX_SECTION_SIZE(pci_fixup_early);
pr_info("PCI fixup size: %d\n", tbl_size);