All of lore.kernel.org
 help / color / mirror / Atom feed
* Updated single-pass kallsyms patchkit for LTO
@ 2014-02-14 21:17 Andi Kleen
  2014-02-14 21:17 ` [PATCH 1/6] kbuild: Remove relocations from kallsyms table Andi Kleen
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek

Mostly fix the padding code build error Markus found.

The single pass code generally improves build performance,
even without LTO.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/6] kbuild: Remove relocations from kallsyms table
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  2014-02-14 21:17 ` [PATCH 2/6] kbuild: Put kallsyms into own section Andi Kleen
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Remove the ELF relocations from the kallsyms_address[] table.
Instead we just store offsets to _text and relocate that while
accessing the kallsyms table. This is done with a new
kallsyms_offsets[] table. With these changes .tmp_kallsyms*.o
becomes relocation free.

In theory this would also allow to shrink the kallsyms table
on 64bit by using offsets.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 kernel/kallsyms.c  | 27 ++++++++++++++++-----------
 scripts/kallsyms.c | 18 ++++++------------
 2 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 3127ad5..e7d7844 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -36,7 +36,7 @@
  * These will be re-linked against their real values
  * during the second link stage.
  */
-extern const unsigned long kallsyms_addresses[] __attribute__((weak));
+extern const long kallsyms_offsets[] __attribute__((weak));
 extern const u8 kallsyms_names[] __attribute__((weak));
 
 /*
@@ -51,6 +51,11 @@ extern const u16 kallsyms_token_index[] __attribute__((weak));
 
 extern const unsigned long kallsyms_markers[] __attribute__((weak));
 
+static inline unsigned long kallsyms_address(int ind)
+{
+	return (unsigned long)RELOC_HIDE(&_text, kallsyms_offsets[ind]);
+}
+
 static inline int is_kernel_inittext(unsigned long addr)
 {
 	if (addr >= (unsigned long)_sinittext
@@ -186,7 +191,7 @@ unsigned long kallsyms_lookup_name(const char *name)
 		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
 
 		if (strcmp(namebuf, name) == 0)
-			return kallsyms_addresses[i];
+			return kallsyms_address(i);
 	}
 	return module_kallsyms_lookup_name(name);
 }
@@ -203,7 +208,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
 
 	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
 		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
-		ret = fn(data, namebuf, NULL, kallsyms_addresses[i]);
+		ret = fn(data, namebuf, NULL, kallsyms_address(i));
 		if (ret != 0)
 			return ret;
 	}
@@ -219,15 +224,15 @@ static unsigned long get_symbol_pos(unsigned long addr,
 	unsigned long i, low, high, mid;
 
 	/* This kernel should never had been booted. */
-	BUG_ON(!kallsyms_addresses);
+	BUG_ON(!kallsyms_offsets);
 
-	/* Do a binary search on the sorted kallsyms_addresses array. */
+	/* Do a binary search on the sorted kallsyms_offsets array. */
 	low = 0;
 	high = kallsyms_num_syms;
 
 	while (high - low > 1) {
 		mid = low + (high - low) / 2;
-		if (kallsyms_addresses[mid] <= addr)
+		if (kallsyms_address(mid) <= addr)
 			low = mid;
 		else
 			high = mid;
@@ -237,15 +242,15 @@ static unsigned long get_symbol_pos(unsigned long addr,
 	 * Search for the first aliased symbol. Aliased
 	 * symbols are symbols with the same address.
 	 */
-	while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
+	while (low && kallsyms_address(low - 1) == kallsyms_address(low))
 		--low;
 
-	symbol_start = kallsyms_addresses[low];
+	symbol_start = kallsyms_address(low);
 
 	/* Search for next non-aliased symbol. */
 	for (i = low + 1; i < kallsyms_num_syms; i++) {
-		if (kallsyms_addresses[i] > symbol_start) {
-			symbol_end = kallsyms_addresses[i];
+		if (kallsyms_address(i) > symbol_start) {
+			symbol_end = kallsyms_address(i);
 			break;
 		}
 	}
@@ -469,7 +474,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
 	unsigned off = iter->nameoff;
 
 	iter->module_name[0] = '\0';
-	iter->value = kallsyms_addresses[iter->pos];
+	iter->value = kallsyms_address(iter->pos);
 
 	iter->type = kallsyms_get_symbol_type(off);
 
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 10085de..56f5986 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -190,7 +190,7 @@ static int symbol_valid(struct sym_entry *s)
 	 * specified so exclude them to get a stable symbol list.
 	 */
 	static char *special_symbols[] = {
-		"kallsyms_addresses",
+		"kallsyms_offsets",
 		"kallsyms_num_syms",
 		"kallsyms_names",
 		"kallsyms_markers",
@@ -322,19 +322,13 @@ static void write_src(void)
 	 * symbols that are declared static and are private to their
 	 * .o files.  This prevents .tmp_kallsyms.o or any other
 	 * object from referencing them.
+	 *
+	 * We do the offsets to _text now in kallsyms.c at runtime,
+	 * to get a relocationless symbol table.
 	 */
-	output_label("kallsyms_addresses");
+	output_label("kallsyms_offsets");
 	for (i = 0; i < table_cnt; i++) {
-		if (toupper(table[i].sym[0]) != 'A') {
-			if (_text <= table[i].addr)
-				printf("\tPTR\t_text + %#llx\n",
-					table[i].addr - _text);
-			else
-				printf("\tPTR\t_text - %#llx\n",
-					_text - table[i].addr);
-		} else {
-			printf("\tPTR\t%#llx\n", table[i].addr);
-		}
+		printf("\tPTR\t%#llx\n", table[i].addr - _text);
 	}
 	printf("\n");
 
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/6] kbuild: Put kallsyms into own section
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
  2014-02-14 21:17 ` [PATCH 1/6] kbuild: Remove relocations from kallsyms table Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  2014-02-14 21:17 ` [PATCH 3/6] kbuild: Don't include const variable in kallsyms with !KALLSYMS_ALL Andi Kleen
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Put the kallsyms information into an own .kallsyms section.
This makes it easier to patch the kallsyms inside the executable.
Otherwise it shouldn't change anything.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 include/asm-generic/vmlinux.lds.h | 4 ++++
 scripts/kallsyms.c                | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bc2121f..6214f18 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -280,6 +280,10 @@
 									\
 	TRACEDATA							\
 									\
+	.kallsyms          : AT(ADDR(.kallsyms) - LOAD_OFFSET) {	\
+		*(.kallsyms)						\
+	}								\
+									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 56f5986..ceef756 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -314,7 +314,7 @@ static void write_src(void)
 	printf("#define ALGN .align 4\n");
 	printf("#endif\n");
 
-	printf("\t.section .rodata, \"a\"\n");
+	printf("\t.section .kallsyms, \"a\"\n");
 
 	/* Provide proper symbols relocatability by their '_text'
 	 * relativeness.  The symbol names cannot be used to construct
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/6] kbuild: Don't include const variable in kallsyms with !KALLSYMS_ALL
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
  2014-02-14 21:17 ` [PATCH 1/6] kbuild: Remove relocations from kallsyms table Andi Kleen
  2014-02-14 21:17 ` [PATCH 2/6] kbuild: Put kallsyms into own section Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  2014-02-14 21:17 ` [PATCH 4/6] kbuild: Support padding in kallsyms tables v2 Andi Kleen
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

const variables are put into the text segment, so !KALLSYMS_ALL
includes them into the kallsyms section. Remove them to make
the kallsyms smaller. This also avoids some problems with LTO.
The way LTO generates the first pass kallsyms cannot handle
variables currently, so if we don't filter them out the
first and second level pass differ too much.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 scripts/kallsyms.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index ceef756..d79027e 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -151,6 +151,11 @@ static int read_symbol(FILE *in, struct sym_entry *s)
 	/* exclude debugging symbols */
 	else if (stype == 'N')
 		return -1;
+	/* Don't include const symbols in the text section
+	 * unless --all-symbols is specified.
+	 */
+	else if (toupper(stype) != 'T' && !all_symbols)
+		return -1;
 
 	/* include the type field in the symbol name, so that it gets
 	 * compressed together */
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] kbuild: Support padding in kallsyms tables v2
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
                   ` (2 preceding siblings ...)
  2014-02-14 21:17 ` [PATCH 3/6] kbuild: Don't include const variable in kallsyms with !KALLSYMS_ALL Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  2014-02-14 21:17 ` [PATCH 5/6] kbuild: Use single pass kallsyms Andi Kleen
  2014-02-14 21:17 ` [PATCH 6/6] kbuild: Remove .dot postfixes in kallsyms Andi Kleen
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Add support for padding the variable length tables in kallsyms.
This adds a new --pad=XXX option to kallsyms to specify the table lengths,
and another option --pad-file=X to write the table lengths to a file.
Then when a table is shorter than the padding add the necessary padding
at the end.

This allows to replace an existing symbol table later with a different
one that may differ slightly.

Add 5% slack for now in case the prediction is too small
(can happen with LTO)

v2: Fix build error, found by Markus Trippelsdorf.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 scripts/kallsyms.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 3 deletions(-)

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index d79027e..293c9eb 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -23,6 +23,13 @@
 #include <string.h>
 #include <ctype.h>
 
+/*
+ * The ratio to increase the padding, by how much the final kallsyms
+ * can be larger. This is for symbols that are not visible before
+ * final linking.
+ */
+#define PAD_RATIO 20 /* 1/x = ~5% */
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 #endif
@@ -41,6 +48,14 @@ struct text_range {
 	unsigned long long start, end;
 };
 
+enum pads {
+	PAD_OFF,
+	PAD_NAMES,
+	PAD_MARKERS,
+	PAD_TOKTAB,
+	NUM_PAD
+};
+
 static unsigned long long _text;
 static struct text_range text_ranges[] = {
 	{ "_stext",     "_etext"     },
@@ -69,6 +84,7 @@ static void usage(void)
 	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
 			"[--symbol-prefix=<prefix char>] "
 			"[--page-offset=<CONFIG_PAGE_OFFSET>] "
+			"[--pad=A,B,C] [--pad-file=name] "
 			"< in.map > out.S\n");
 	exit(1);
 }
@@ -303,7 +319,14 @@ static int expand_symbol(unsigned char *data, int len, char *result)
 	return total;
 }
 
-static void write_src(void)
+static void bad_padding(char *msg, int diff)
+{
+	fprintf(stderr, "kallsyms: %s padding too short: %d missing\n",
+			msg, diff);
+	exit(EXIT_FAILURE);
+}
+
+static void write_src(int *pad, int *opad)
 {
 	unsigned int i, k, off;
 	unsigned int best_idx[256];
@@ -335,6 +358,16 @@ static void write_src(void)
 	for (i = 0; i < table_cnt; i++) {
 		printf("\tPTR\t%#llx\n", table[i].addr - _text);
 	}
+	if (pad) {
+		if (i > pad[PAD_OFF])
+			bad_padding("address pointers", i - pad[PAD_OFF]);
+		for (; i < pad[PAD_OFF]; i++)
+			printf("\tPTR\t0\n");
+	} else {
+		for (i = 0; i < table_cnt / PAD_RATIO; i++)
+			printf("\tPTR\t0\n");
+		opad[PAD_OFF] = table_cnt + table_cnt/PAD_RATIO;
+	}
 	printf("\n");
 
 	output_label("kallsyms_num_syms");
@@ -363,11 +396,31 @@ static void write_src(void)
 
 		off += table[i].len + 1;
 	}
+	if (pad) {
+		if (off > pad[PAD_NAMES])
+			bad_padding("name table", off - pad[PAD_NAMES]);
+		if (off < pad[PAD_NAMES])
+			printf("\t.fill %d,1,0\n", pad[PAD_NAMES] - off);
+	} else {
+		printf("\t.fill %d,1,0\n", off/PAD_RATIO);
+		off += off/PAD_RATIO;
+		opad[PAD_NAMES] = off;
+	}
 	printf("\n");
 
 	output_label("kallsyms_markers");
 	for (i = 0; i < ((table_cnt + 255) >> 8); i++)
 		printf("\tPTR\t%d\n", markers[i]);
+	if (pad) {
+		if (i > pad[PAD_MARKERS])
+			bad_padding("markers", i - pad[PAD_MARKERS]);
+		for (; i < pad[PAD_MARKERS]; i++)
+			printf("\tPTR\t0\n");
+	} else {
+		for (k = 0; k < i/PAD_RATIO; k++)
+			printf("\tPTR\t0\n");
+		opad[PAD_MARKERS] = i + i/PAD_RATIO;
+	}
 	printf("\n");
 
 	free(markers);
@@ -380,6 +433,16 @@ static void write_src(void)
 		printf("\t.asciz\t\"%s\"\n", buf);
 		off += strlen(buf) + 1;
 	}
+	if (pad) {
+		if (off > pad[PAD_TOKTAB])
+			bad_padding("token table", off - pad[PAD_TOKTAB]);
+		if (off < pad[PAD_TOKTAB])
+			printf("\t.fill %d,1,0\n", pad[PAD_TOKTAB] - off);
+	} else {
+		printf("\t.fill %d,1,0\n", off/PAD_RATIO);
+		off += off/PAD_RATIO;
+		opad[PAD_TOKTAB] = off;
+	}
 	printf("\n");
 
 	output_label("kallsyms_token_index");
@@ -647,6 +710,10 @@ static void sort_symbols(void)
 
 int main(int argc, char **argv)
 {
+	int inpad[NUM_PAD], opad[NUM_PAD];
+	int *inpadp = NULL;
+	FILE *opadf = NULL;
+
 	if (argc >= 2) {
 		int i;
 		for (i = 1; i < argc; i++) {
@@ -661,6 +728,22 @@ int main(int argc, char **argv)
 			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
 				const char *p = &argv[i][14];
 				kernel_start_addr = strtoull(p, NULL, 16);
+			} else if (strncmp(argv[i], "--pad=", 6) == 0) {
+				inpadp = inpad;
+				if (sscanf(argv[i] + 6, "%d,%d,%d,%d",
+					   inpad + 0,
+					   inpad + 1,
+					   inpad + 2,
+					   inpad + 3) != NUM_PAD) {
+					fprintf(stderr, "Bad pad list\n");
+					exit(EXIT_FAILURE);
+				}
+			} else if (strncmp(argv[i], "--pad-file=", 11) == 0) {
+				opadf = fopen(argv[i] + 11, "w");
+				if (!opadf) {
+					fprintf(stderr, "Cannot open %s", argv[i]+11);
+					exit(EXIT_FAILURE);
+				}
 			} else
 				usage();
 		}
@@ -670,7 +753,11 @@ int main(int argc, char **argv)
 	read_map(stdin);
 	sort_symbols();
 	optimize_token_table();
-	write_src();
-
+	write_src(inpadp, opad);
+	if (opadf) {
+		fprintf(opadf, "--pad=%d,%d,%d,%d\n",
+			opad[0], opad[1], opad[2], opad[3]);
+		fclose(opadf);
+	}
 	return 0;
 }
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/6] kbuild: Use single pass kallsyms
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
                   ` (3 preceding siblings ...)
  2014-02-14 21:17 ` [PATCH 4/6] kbuild: Support padding in kallsyms tables v2 Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  2014-02-14 21:17 ` [PATCH 6/6] kbuild: Remove .dot postfixes in kallsyms Andi Kleen
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

kallsyms currenly links the kernel upto three times
(in addition to another one for modpost checks)

Linking can be a quite slow operation, especially when
the kernel has a lot of debug information (lots of IO),
or Link Time Optimization is used.

Final linking is also a non parallelizable bottlneck, so it's
always good to do it less.

Use a different kallsyms method to avoid this:
- generate a initial kallsyms table from the top level
object files
- This table is usually a super set of the final table,
but without final addresses and some extra symbols
(e.g. discard and local symbols)
- Use this table to link the vmlinux
- Then generate a new kallsyms table with padding so
that all symbols stay at the same offsets. This works
because the new table is smaller or the same than the
original one.
We let the first kallsyms generate a padding file and
then use it on the next link.
- Then finally patch in the new table into the vmlinux

The size difference between the two tables is typically
small, so the additional padding is not a problem
(a few hundred bytes in my kernels)

Right now we still do two links. One to generate
the kernel, and another one to generate the vmlinux.o
for modpost.

On my slowish laptop this cuts down the final serialized phase
of a moderate size kernel build (just relinking vmlinux) by 1/3,
from ~30s to 20s

Tested on x86, tests on other architectures would be appreciated.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 scripts/Makefile        |  2 +-
 scripts/elf_file_offset | 24 +++++++++++++
 scripts/kallsyms.c      | 10 ++++--
 scripts/link-vmlinux.sh | 92 ++++++++++++++++++++-----------------------------
 scripts/patchfile.c     | 81 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 151 insertions(+), 58 deletions(-)
 create mode 100644 scripts/elf_file_offset
 create mode 100644 scripts/patchfile.c

diff --git a/scripts/Makefile b/scripts/Makefile
index 01e7adb..9c84464 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -10,7 +10,7 @@
 
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
-hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
+hostprogs-$(CONFIG_KALLSYMS)     += kallsyms patchfile
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_IKCONFIG)     += bin2c
diff --git a/scripts/elf_file_offset b/scripts/elf_file_offset
new file mode 100644
index 0000000..2c8ee49
--- /dev/null
+++ b/scripts/elf_file_offset
@@ -0,0 +1,24 @@
+#!/bin/bash
+# find the file offset of a section in a ELF file
+# objdump --section-headers elf-file |
+# gawk -f elf_file_offset filesize=SIZE section=SECTIONNAME
+# gawk needed for strtonum()
+#Idx Name          Size      VMA               LMA               File off  Algn
+#  4 .kallsyms     001fd648  ffffffff81b1c068  0000000001b1c068  00d1c068  2**3
+
+$2 == section {
+	old = strtonum("0x" $3)
+	new = strtonum(filesize)
+	if (old < new) {
+		print "Not enough padding in vmlinux for new kallsyms, missing",new-old > "/dev/stderr"
+		print "Please lower (=increase) PAD_RATIO in kallsyms.c"
+		exit 1
+	}
+	print "0x" $6
+	# XXX doesn't exit in gawk 4.1.0 ?!?
+	#exit(0)
+}
+#END {
+#    print section " not found" > "/dev/stderr"
+#    exit 1
+#}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 293c9eb..566e53e 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -192,15 +192,19 @@ static int symbol_valid_tr(struct sym_entry *s)
 {
 	size_t i;
 	struct text_range *tr;
+	int valid = 0;
 
 	for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
 		tr = &text_ranges[i];
 
+		if (tr->start && tr->end)
+			valid++;
+
 		if (s->addr >= tr->start && s->addr <= tr->end)
 			return 1;
 	}
 
-	return 0;
+	return valid ? 0 : 1;
 }
 
 static int symbol_valid(struct sym_entry *s)
@@ -242,11 +246,13 @@ static int symbol_valid(struct sym_entry *s)
 		 * the kallsyms data are added.  If these symbols move then
 		 * they may get dropped in pass 2, which breaks the kallsyms
 		 * rules.
+		 * But don't do this for predicted fake symbols with 0 value.
 		 */
-		if ((s->addr == text_range_text->end &&
+		if (((s->addr == text_range_text->end &&
 				strcmp((char *)s->sym + offset, text_range_text->etext)) ||
 		    (s->addr == text_range_inittext->end &&
 				strcmp((char *)s->sym + offset, text_range_inittext->etext)))
+			&& text_range_text->end != 0)
 			return 0;
 	}
 
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 2dcb377..b299fdd 100644
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 #
 # link vmlinux
 #
@@ -85,11 +85,13 @@ kallsyms()
 	if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
+	kallsymopt="${kallsymopt} $3"
 
 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 
 	${NM} -n ${1} | \
+		awk 'NF == 3 { print}' |
 		scripts/kallsyms ${kallsymopt} | \
 		${CC} ${aflags} -c -o ${2} -x assembler-with-cpp -
 }
@@ -166,51 +168,43 @@ ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init
 
 kallsymso=""
 kallsyms_vmlinux=""
-if [ -n "${CONFIG_KALLSYMS}" ]; then
-
-	# kallsyms support
-	# Generate section listing all symbols and add it into vmlinux
-	# It's a three step process:
-	# 1)  Link .tmp_vmlinux1 so it has all symbols and sections,
-	#     but __kallsyms is empty.
-	#     Running kallsyms on that gives us .tmp_kallsyms1.o with
-	#     the right size
-	# 2)  Link .tmp_vmlinux2 so it now has a __kallsyms section of
-	#     the right size, but due to the added section, some
-	#     addresses have shifted.
-	#     From here, we generate a correct .tmp_kallsyms2.o
-	# 2a) We may use an extra pass as this has been necessary to
-	#     woraround some alignment related bugs.
-	#     KALLSYMS_EXTRA_PASS=1 is used to trigger this.
-	# 3)  The correct ${kallsymso} is linked into the final vmlinux.
-	#
-	# a)  Verify that the System.map from vmlinux matches the map from
-	#     ${kallsymso}.
-
-	kallsymso=.tmp_kallsyms2.o
-	kallsyms_vmlinux=.tmp_vmlinux2
-
-	# step 1
-	vmlinux_link "" .tmp_vmlinux1
-	kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o
-
-	# step 2
-	vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2
-	kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o
-
-	# step 2a
-	if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
-		kallsymso=.tmp_kallsyms3.o
-		kallsyms_vmlinux=.tmp_vmlinux3
-
-		vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3
-
-		kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o
-	fi
+
+if [ -n "${CONFIG_KALLSYMS}" ] ; then
+	# Generate kallsyms from the top level object files
+	# this is slightly off, and has wrong addresses,
+	# but gives us the conservative max length of the kallsyms
+	# table to link in something with the size.
+	info KALLSYMS1 .tmp_kallsyms1.o
+	kallsyms "${KBUILD_VMLINUX_INIT} ${KBUILD_VMLINUX_MAIN}" \
+		 .tmp_kallsyms1.o \
+		 "--pad-file=.kallsyms_pad"
+	kallsymsso=.tmp_kallsyms1.o
 fi
 
 info LD vmlinux
-vmlinux_link "${kallsymso}" vmlinux
+vmlinux_link "${kallsymsso}" vmlinux
+if [ -n "${CONFIG_KALLSYMS}" ] ; then
+	# Now regenerate the kallsyms table and patch it into the
+	# previously linked file. We tell kallsyms to pad it
+	# to the previous length, so that no symbol changes.
+	info KALLSYMS2 .tmp_kallsyms2.o
+	kallsyms vmlinux .tmp_kallsyms2.o $(<.kallsyms_pad)
+
+	info OBJCOPY .tmp_kallsyms2.bin
+	${OBJCOPY} -O binary .tmp_kallsyms2.o .tmp_kallsyms2.bin
+
+	info PATCHFILE vmlinux
+	EF=scripts/elf_file_offset
+	if [ ! -r $EF ] ; then EF=source/$EF ; fi
+	OFF=$(${OBJDUMP} --section-headers vmlinux |
+	     gawk -f $EF \
+	-v section=.kallsyms -v filesize=$(stat -c%s .tmp_kallsyms2.bin) )
+	if [ -z "$OFF" ] ; then
+		echo "Cannot find .kallsyms section in vmlinux binary"
+		exit 1
+	fi
+	scripts/patchfile vmlinux $OFF .tmp_kallsyms2.bin
+fi
 
 if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then
 	info SORTEX vmlinux
@@ -220,17 +214,5 @@ fi
 info SYSMAP System.map
 mksysmap vmlinux System.map
 
-# step a (see comment above)
-if [ -n "${CONFIG_KALLSYMS}" ]; then
-	mksysmap ${kallsyms_vmlinux} .tmp_System.map
-
-	if ! cmp -s System.map .tmp_System.map; then
-		echo >&2 Inconsistent kallsyms data
-		echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
-		cleanup
-		exit 1
-	fi
-fi
-
 # We made a new kernel - delete old version file
 rm -f .old_version
diff --git a/scripts/patchfile.c b/scripts/patchfile.c
new file mode 100644
index 0000000..1a3414d
--- /dev/null
+++ b/scripts/patchfile.c
@@ -0,0 +1,81 @@
+/* Patch file at specific offset
+ * patchfile file-to-patch offset patch-file [len-of-patch]
+ */
+#define _GNU_SOURCE 1
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1))
+
+static void *mmapfile(char *file, size_t *size)
+{
+	int pagesize = sysconf(_SC_PAGESIZE);
+	int fd = open(file, O_RDONLY);
+	void *res = NULL;
+	struct stat st;
+
+	*size = 0;
+	if (fd < 0)
+		return NULL;
+	if (fstat(fd, &st) >= 0) {
+		*size = st.st_size;
+		res = mmap(NULL, ROUNDUP(st.st_size, pagesize),
+				PROT_READ, MAP_SHARED,
+				fd, 0);
+		if (res == (void *)-1)
+			res = NULL;
+	}
+	close(fd);
+	return res;
+}
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: patchfile file-to-patch offset file-to-patch-in\n");
+	exit(1);
+}
+
+static size_t get_num(char *s)
+{
+	char *endp;
+	size_t v = strtoul(s, &endp, 0);
+	if (s == endp)
+		usage();
+	return v;
+}
+
+int main(int ac, char **av)
+{
+	char *patch;
+	size_t patchsize;
+	int infd;
+	size_t offset;
+
+	if (ac != 5 && ac != 4)
+		usage();
+	offset = get_num(av[2]);
+	patch = mmapfile(av[3], &patchsize);
+	if (av[4]) {
+		size_t newsize = get_num(av[4]);
+		if (newsize > patchsize)
+			fprintf(stderr, "kallsyms: warning, size larger than patch\n");
+		if (newsize < patchsize)
+			patchsize = newsize;
+	}
+	infd = open(av[1], O_RDWR);
+	if (infd < 0) {
+		fprintf(stderr, "Cannot open %s\n", av[1]);
+		exit(1);
+	}
+	if (pwrite(infd, patch, patchsize, offset) != patchsize) {
+		fprintf(stderr, "Cannot write patch to %s\n", av[1]);
+		exit(1);
+	}
+	close(infd);
+	return 0;
+}
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/6] kbuild: Remove .dot postfixes in kallsyms
  2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
                   ` (4 preceding siblings ...)
  2014-02-14 21:17 ` [PATCH 5/6] kbuild: Use single pass kallsyms Andi Kleen
@ 2014-02-14 21:17 ` Andi Kleen
  5 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-14 21:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: x86, linux-kbuild, mmarek, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

For static and some LTO symbols gcc generates .XXXX postfixes.
Remove those from the kallsyms, as they are not useful to the user
and makes it much larger. This also avoids some issues with LTO.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 scripts/kallsyms.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 566e53e..94e0502 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -122,7 +122,7 @@ static int read_symbol_tr(const char *sym, unsigned long long addr)
 static int read_symbol(FILE *in, struct sym_entry *s)
 {
 	char str[500];
-	char *sym, stype;
+	char *sym, stype, *dot;
 	int rc;
 
 	rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
@@ -138,6 +138,11 @@ static int read_symbol(FILE *in, struct sym_entry *s)
 		return -1;
 	}
 
+	/* Drop static .XXXX postfixes */
+	dot = strchr(str, '.');
+	if (dot)
+		*dot = 0;
+
 	sym = str;
 	/* skip prefix char */
 	if (symbol_prefix_char && str[0] == symbol_prefix_char)
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] kbuild: Support padding in kallsyms tables v2
  2014-02-18 14:24 Single pass kallsyms v3 Andi Kleen
@ 2014-02-18 14:24 ` Andi Kleen
  0 siblings, 0 replies; 8+ messages in thread
From: Andi Kleen @ 2014-02-18 14:24 UTC (permalink / raw)
  To: linux-kernel; +Cc: sam, x86, linux-kbuild, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Add support for padding the variable length tables in kallsyms.
This adds a new --pad=XXX option to kallsyms to specify the table lengths,
and another option --pad-file=X to write the table lengths to a file.
Then when a table is shorter than the padding add the necessary padding
at the end.

This allows to replace an existing symbol table later with a different
one that may differ slightly.

Add 5% slack for now in case the prediction is too small
(can happen with LTO)

v2: Fix build error, found by Markus Trippelsdorf.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 scripts/kallsyms.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 3 deletions(-)

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index d79027e..293c9eb 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -23,6 +23,13 @@
 #include <string.h>
 #include <ctype.h>
 
+/*
+ * The ratio to increase the padding, by how much the final kallsyms
+ * can be larger. This is for symbols that are not visible before
+ * final linking.
+ */
+#define PAD_RATIO 20 /* 1/x = ~5% */
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 #endif
@@ -41,6 +48,14 @@ struct text_range {
 	unsigned long long start, end;
 };
 
+enum pads {
+	PAD_OFF,
+	PAD_NAMES,
+	PAD_MARKERS,
+	PAD_TOKTAB,
+	NUM_PAD
+};
+
 static unsigned long long _text;
 static struct text_range text_ranges[] = {
 	{ "_stext",     "_etext"     },
@@ -69,6 +84,7 @@ static void usage(void)
 	fprintf(stderr, "Usage: kallsyms [--all-symbols] "
 			"[--symbol-prefix=<prefix char>] "
 			"[--page-offset=<CONFIG_PAGE_OFFSET>] "
+			"[--pad=A,B,C] [--pad-file=name] "
 			"< in.map > out.S\n");
 	exit(1);
 }
@@ -303,7 +319,14 @@ static int expand_symbol(unsigned char *data, int len, char *result)
 	return total;
 }
 
-static void write_src(void)
+static void bad_padding(char *msg, int diff)
+{
+	fprintf(stderr, "kallsyms: %s padding too short: %d missing\n",
+			msg, diff);
+	exit(EXIT_FAILURE);
+}
+
+static void write_src(int *pad, int *opad)
 {
 	unsigned int i, k, off;
 	unsigned int best_idx[256];
@@ -335,6 +358,16 @@ static void write_src(void)
 	for (i = 0; i < table_cnt; i++) {
 		printf("\tPTR\t%#llx\n", table[i].addr - _text);
 	}
+	if (pad) {
+		if (i > pad[PAD_OFF])
+			bad_padding("address pointers", i - pad[PAD_OFF]);
+		for (; i < pad[PAD_OFF]; i++)
+			printf("\tPTR\t0\n");
+	} else {
+		for (i = 0; i < table_cnt / PAD_RATIO; i++)
+			printf("\tPTR\t0\n");
+		opad[PAD_OFF] = table_cnt + table_cnt/PAD_RATIO;
+	}
 	printf("\n");
 
 	output_label("kallsyms_num_syms");
@@ -363,11 +396,31 @@ static void write_src(void)
 
 		off += table[i].len + 1;
 	}
+	if (pad) {
+		if (off > pad[PAD_NAMES])
+			bad_padding("name table", off - pad[PAD_NAMES]);
+		if (off < pad[PAD_NAMES])
+			printf("\t.fill %d,1,0\n", pad[PAD_NAMES] - off);
+	} else {
+		printf("\t.fill %d,1,0\n", off/PAD_RATIO);
+		off += off/PAD_RATIO;
+		opad[PAD_NAMES] = off;
+	}
 	printf("\n");
 
 	output_label("kallsyms_markers");
 	for (i = 0; i < ((table_cnt + 255) >> 8); i++)
 		printf("\tPTR\t%d\n", markers[i]);
+	if (pad) {
+		if (i > pad[PAD_MARKERS])
+			bad_padding("markers", i - pad[PAD_MARKERS]);
+		for (; i < pad[PAD_MARKERS]; i++)
+			printf("\tPTR\t0\n");
+	} else {
+		for (k = 0; k < i/PAD_RATIO; k++)
+			printf("\tPTR\t0\n");
+		opad[PAD_MARKERS] = i + i/PAD_RATIO;
+	}
 	printf("\n");
 
 	free(markers);
@@ -380,6 +433,16 @@ static void write_src(void)
 		printf("\t.asciz\t\"%s\"\n", buf);
 		off += strlen(buf) + 1;
 	}
+	if (pad) {
+		if (off > pad[PAD_TOKTAB])
+			bad_padding("token table", off - pad[PAD_TOKTAB]);
+		if (off < pad[PAD_TOKTAB])
+			printf("\t.fill %d,1,0\n", pad[PAD_TOKTAB] - off);
+	} else {
+		printf("\t.fill %d,1,0\n", off/PAD_RATIO);
+		off += off/PAD_RATIO;
+		opad[PAD_TOKTAB] = off;
+	}
 	printf("\n");
 
 	output_label("kallsyms_token_index");
@@ -647,6 +710,10 @@ static void sort_symbols(void)
 
 int main(int argc, char **argv)
 {
+	int inpad[NUM_PAD], opad[NUM_PAD];
+	int *inpadp = NULL;
+	FILE *opadf = NULL;
+
 	if (argc >= 2) {
 		int i;
 		for (i = 1; i < argc; i++) {
@@ -661,6 +728,22 @@ int main(int argc, char **argv)
 			} else if (strncmp(argv[i], "--page-offset=", 14) == 0) {
 				const char *p = &argv[i][14];
 				kernel_start_addr = strtoull(p, NULL, 16);
+			} else if (strncmp(argv[i], "--pad=", 6) == 0) {
+				inpadp = inpad;
+				if (sscanf(argv[i] + 6, "%d,%d,%d,%d",
+					   inpad + 0,
+					   inpad + 1,
+					   inpad + 2,
+					   inpad + 3) != NUM_PAD) {
+					fprintf(stderr, "Bad pad list\n");
+					exit(EXIT_FAILURE);
+				}
+			} else if (strncmp(argv[i], "--pad-file=", 11) == 0) {
+				opadf = fopen(argv[i] + 11, "w");
+				if (!opadf) {
+					fprintf(stderr, "Cannot open %s", argv[i]+11);
+					exit(EXIT_FAILURE);
+				}
 			} else
 				usage();
 		}
@@ -670,7 +753,11 @@ int main(int argc, char **argv)
 	read_map(stdin);
 	sort_symbols();
 	optimize_token_table();
-	write_src();
-
+	write_src(inpadp, opad);
+	if (opadf) {
+		fprintf(opadf, "--pad=%d,%d,%d,%d\n",
+			opad[0], opad[1], opad[2], opad[3]);
+		fclose(opadf);
+	}
 	return 0;
 }
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-02-18 14:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-14 21:17 Updated single-pass kallsyms patchkit for LTO Andi Kleen
2014-02-14 21:17 ` [PATCH 1/6] kbuild: Remove relocations from kallsyms table Andi Kleen
2014-02-14 21:17 ` [PATCH 2/6] kbuild: Put kallsyms into own section Andi Kleen
2014-02-14 21:17 ` [PATCH 3/6] kbuild: Don't include const variable in kallsyms with !KALLSYMS_ALL Andi Kleen
2014-02-14 21:17 ` [PATCH 4/6] kbuild: Support padding in kallsyms tables v2 Andi Kleen
2014-02-14 21:17 ` [PATCH 5/6] kbuild: Use single pass kallsyms Andi Kleen
2014-02-14 21:17 ` [PATCH 6/6] kbuild: Remove .dot postfixes in kallsyms Andi Kleen
2014-02-18 14:24 Single pass kallsyms v3 Andi Kleen
2014-02-18 14:24 ` [PATCH 4/6] kbuild: Support padding in kallsyms tables v2 Andi Kleen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.