kbuild: warn about ld added unique sections
authorSam Ravnborg <sam@ravnborg.org>
Mon, 28 Jan 2008 19:13:13 +0000 (20:13 +0100)
committerSam Ravnborg <sam@ravnborg.org>
Mon, 28 Jan 2008 22:21:19 +0000 (23:21 +0100)
If there is a mixture of specifying sections for code in gcc
and assembler then if the assembler code do not add
the "ax" flags the linker will see this as two different sections
and generate unique sections for each. ld does so by adding a dot
and a number.
Teach modpost to warn if a section shows up that match this
pattern - but do this only for non-debug sections.

It will result in warnings like this:

WARNING: vmlinux.o (.sched.text.1): unexpected section name.
The (.[number]+) following section name are ld generated and not expected.
Did you forget to use "ax"/"aw" in a .S file?
Note that for example <linux/init.h> contains
section definitions for use in .S files.

All warnings seen with a defconfig build for:
x86 (32+64bit) and sparc64 has been fixed (via respective maintainers).

arm, powerpc (64 bit), s390 (32 bit), ia64, alpha, sh4 checked - no
warnings seen with a defconfig build.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
scripts/mod/modpost.c

index 3cf1ba8..f8efc93 100644 (file)
@@ -696,6 +696,43 @@ int match(const char *sym, const char * const pat[])
 static const char *section_white_list[] =
        { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
 
+/*
+ * Is this section one we do not want to check?
+ * This is often debug sections.
+ * If we are going to check this section then
+ * test if section name ends with a dot and a number.
+ * This is used to find sections where the linker have
+ * appended a dot-number to make the name unique.
+ * The cause of this is often a section specified in assembler
+ * without "ax" / "aw" and the same section used in .c
+ * code where gcc add these.
+ */
+static int check_section(const char *modname, const char *sec)
+{
+       const char *e = sec + strlen(sec) - 1;
+       if (match(sec, section_white_list))
+               return 1;
+
+       if (*e && isdigit(*e)) {
+               /* consume all digits */
+               while (*e && e != sec && isdigit(*e))
+                       e--;
+               if (*e == '.') {
+                       warn("%s (%s): unexpected section name.\n"
+                            "The (.[number]+) following section name are "
+                            "ld generated and not expected.\n"
+                            "Did you forget to use \"ax\"/\"aw\" "
+                            "in a .S file?\n"
+                            "Note that for example <linux/init.h> contains\n"
+                            "section definitions for use in .S files.\n\n",
+                            modname, sec);
+               }
+       }
+       return 0;
+}
+
+
+
 #define ALL_INIT_DATA_SECTIONS \
        ".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
 #define ALL_EXIT_DATA_SECTIONS \
@@ -1311,8 +1348,9 @@ static void section_rela(const char *modname, struct elf_info *elf,
        fromsec = sech_name(elf, sechdr);
        fromsec += strlen(".rela");
        /* if from section (name) is know good then skip it */
-       if (match(fromsec, section_white_list))
+       if (check_section(modname, fromsec))
                return;
+
        for (rela = start; rela < stop; rela++) {
                r.r_offset = TO_NATIVE(rela->r_offset);
 #if KERNEL_ELFCLASS == ELFCLASS64
@@ -1354,7 +1392,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
        fromsec = sech_name(elf, sechdr);
        fromsec += strlen(".rel");
        /* if from section (name) is know good then skip it */
-       if (match(fromsec, section_white_list))
+       if (check_section(modname, fromsec))
                return;
 
        for (rel = start; rel < stop; rel++) {