Merge master.kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6
[linux-drm-fsl-dcu.git] / scripts / mod / modpost.c
index 47bef62eecd7a38e806562617789c26f43ca0c41..65bdfdb56877ee0297d9e605384caedbcbed286c 100644 (file)
@@ -641,12 +641,20 @@ static int secref_whitelist(const char *modname, const char *tosec,
        if (f1 && f2)
                return 1;
 
-       /* Whitelist all references from .pci_fixup section if vmlinux */
+       /* Whitelist all references from .pci_fixup section if vmlinux
+        * Whitelist all refereces from .text.head to .init.data if vmlinux
+        * Whitelist all refereces from .text.head to .init.text if vmlinux
+        */
        if (is_vmlinux(modname)) {
                if ((strcmp(fromsec, ".pci_fixup") == 0) &&
                    (strcmp(tosec, ".init.text") == 0))
                return 1;
 
+               if ((strcmp(fromsec, ".text.head") == 0) &&
+                       ((strcmp(tosec, ".init.data") == 0) ||
+                       (strcmp(tosec, ".init.text") == 0)))
+               return 1;
+
                /* Check for pattern 3 */
                for (s = pat3refsym; *s; s++)
                        if (strcmp(refsymname, *s) == 0)
@@ -678,6 +686,30 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
        return NULL;
 }
 
+static inline int is_arm_mapping_symbol(const char *str)
+{
+       return str[0] == '$' && strchr("atd", str[1])
+              && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+       const char *name = elf->strtab + sym->st_name;
+
+       if (!name || !strlen(name))
+               return 0;
+       return !is_arm_mapping_symbol(name);
+}
+
 /*
  * Find symbols before or equal addr and after addr - in the section sec.
  * If we find two symbols with equal offset prefer one with a valid name.
@@ -706,16 +738,15 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
                if (strcmp(symsec, sec) != 0)
                        continue;
+               if (!is_valid_name(elf, sym))
+                       continue;
                if (sym->st_value <= addr) {
                        if ((addr - sym->st_value) < beforediff) {
                                beforediff = addr - sym->st_value;
                                *before = sym;
                        }
                        else if ((addr - sym->st_value) == beforediff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *before = sym;
+                               *before = sym;
                        }
                }
                else
@@ -725,10 +756,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                *after = sym;
                        }
                        else if ((sym->st_value - addr) == afterdiff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *after = sym;
+                               *after = sym;
                        }
                }
        }