Commit 377f9b8c authored by Richard Henderson's avatar Richard Henderson

[MODULES] Centralize undefined symbol checks; handle undef weak.

parent 291b901b
...@@ -190,15 +190,10 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, ...@@ -190,15 +190,10 @@ apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
/* This is where to make the change. */ /* This is where to make the change. */
location = base + rela[i].r_offset; location = base + rela[i].r_offset;
/* This is the symbol it is referring to. */ /* This is the symbol it is referring to. Note that all
unresolved symbols have been resolved. */
sym = symtab + r_sym; sym = symtab + r_sym;
value = sym->st_value; value = sym->st_value + rela[i].r_addend;
if (!value) {
printk(KERN_ERR "module %s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
value += rela[i].r_addend;
switch (r_type) { switch (r_type) {
case R_ALPHA_NONE: case R_ALPHA_NONE:
......
...@@ -98,11 +98,6 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, ...@@ -98,11 +98,6 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
} }
sym = ((Elf32_Sym *)symsec->sh_addr) + offset; sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
if (!sym->st_value) {
printk(KERN_WARNING "%s: unknown symbol %s\n",
module->name, strtab + sym->st_name);
return -ENOENT;
}
if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
printk(KERN_ERR "%s: out of bounds relocation, " printk(KERN_ERR "%s: out of bounds relocation, "
......
...@@ -70,14 +70,10 @@ int apply_relocate(Elf32_Shdr *sechdrs, ...@@ -70,14 +70,10 @@ int apply_relocate(Elf32_Shdr *sechdrs,
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset; + rel[i].r_offset;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info); + ELF32_R_SYM(rel[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
switch (ELF32_R_TYPE(rel[i].r_info)) { switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_386_32: case R_386_32:
......
...@@ -197,14 +197,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -197,14 +197,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rela[i].r_offset; + rela[i].r_offset;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rela[i].r_info); + ELF32_R_SYM(rela[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
module->name, strtab + sym->st_name);
return -ENOENT;
}
/* `Everything is relative'. */ /* `Everything is relative'. */
value = sym->st_value + rela[i].r_addend; value = sym->st_value + rela[i].r_addend;
......
/* /*
* arch/s390x/kernel/module.c - Kernel module help for s390x. * arch/s390/kernel/module.c - Kernel module help for s390.
* *
* S390 version * S390 version
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
...@@ -77,14 +77,10 @@ int apply_relocate(Elf_Shdr *sechdrs, ...@@ -77,14 +77,10 @@ int apply_relocate(Elf_Shdr *sechdrs,
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset; + rel[i].r_offset;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr
+ ELFW(R_SYM)(rel[i].r_info); + ELFW(R_SYM)(rel[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
switch (ELF_R_TYPE(rel[i].r_info)) { switch (ELF_R_TYPE(rel[i].r_info)) {
case R_390_8: /* Direct 8 bit. */ case R_390_8: /* Direct 8 bit. */
......
...@@ -78,14 +78,10 @@ int apply_relocate(Elf_Shdr *sechdrs, ...@@ -78,14 +78,10 @@ int apply_relocate(Elf_Shdr *sechdrs,
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset; + rel[i].r_offset;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr sym = (ElfW(Sym) *)sechdrs[symindex].sh_addr
+ ELFW(R_SYM)(rel[i].r_info); + ELFW(R_SYM)(rel[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
switch (ELF_R_TYPE(rel[i].r_info)) { switch (ELF_R_TYPE(rel[i].r_info)) {
case R_390_8: /* Direct 8 bit. */ case R_390_8: /* Direct 8 bit. */
......
...@@ -75,15 +75,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -75,15 +75,11 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset; + rel[i].r_offset;
loc32 = (u32 *) location; loc32 = (u32 *) location;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info); + ELF32_R_SYM(rel[i].r_info);
if (!(v = sym->st_value)) { v = sym->st_value + rel[i].r_addend;
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
v += rel[i].r_addend;
switch (ELF32_R_TYPE(rel[i].r_info)) { switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_SPARC_32: case R_SPARC_32:
......
...@@ -185,15 +185,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, ...@@ -185,15 +185,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
BUG_ON(((u64)location >> (u64)32) != (u64)0); BUG_ON(((u64)location >> (u64)32) != (u64)0);
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf64_Sym *)sechdrs[symindex].sh_addr sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+ ELF64_R_SYM(rel[i].r_info); + ELF64_R_SYM(rel[i].r_info);
if (!(v = sym->st_value)) { v = sym->st_value + rel[i].r_addend;
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
v += rel[i].r_addend;
switch (ELF64_R_TYPE(rel[i].r_info) & 0xff) { switch (ELF64_R_TYPE(rel[i].r_info) & 0xff) {
case R_SPARC_64: case R_SPARC_64:
......
...@@ -184,19 +184,12 @@ int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab, ...@@ -184,19 +184,12 @@ int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab,
uint32_t *loc uint32_t *loc
= ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rela[i].r_offset); + rela[i].r_offset);
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
Elf32_Sym *sym Elf32_Sym *sym
= ((Elf32_Sym *)sechdrs[symindex].sh_addr = ((Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM (rela[i].r_info)); + ELF32_R_SYM (rela[i].r_info));
uint32_t val = sym->st_value; uint32_t val = sym->st_value + rela[i].r_addend;
if (! val) {
printk (KERN_WARNING "%s: Unknown symbol %s\n",
mod->name, strtab + sym->st_name);
return -ENOENT;
}
val += rela[i].r_addend;
switch (ELF32_R_TYPE (rela[i].r_info)) { switch (ELF32_R_TYPE (rela[i].r_info)) {
case R_V850_32: case R_V850_32:
......
...@@ -53,14 +53,10 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, ...@@ -53,14 +53,10 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset; + rel[i].r_offset;
/* This is the symbol it is referring to */ /* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf64_Sym *)sechdrs[symindex].sh_addr sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+ ELF64_R_SYM(rel[i].r_info); + ELF64_R_SYM(rel[i].r_info);
if (!sym->st_value) {
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
(int)ELF64_R_TYPE(rel[i].r_info), (int)ELF64_R_TYPE(rel[i].r_info),
......
...@@ -156,11 +156,12 @@ typedef __s64 Elf64_Sxword; ...@@ -156,11 +156,12 @@ typedef __s64 Elf64_Sxword;
#define STT_SECTION 3 #define STT_SECTION 3
#define STT_FILE 4 #define STT_FILE 4
#define ELF32_ST_BIND(x) ((x) >> 4) #define ELF_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf) #define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
/* Symbolic values for the entries in the auxiliary table /* Symbolic values for the entries in the auxiliary table
put on the initial stack */ put on the initial stack */
......
...@@ -5,14 +5,6 @@ ...@@ -5,14 +5,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/elf.h> #include <linux/elf.h>
/* Helper function for arch-specific module loaders */
unsigned long find_symbol_internal(Elf_Shdr *sechdrs,
unsigned int symindex,
const char *strtab,
const char *name,
struct module *mod,
struct kernel_symbol_group **group);
/* These must be implemented by the specific architecture */ /* These must be implemented by the specific architecture */
/* Adjust arch-specific sections. Return 0 on success. */ /* Adjust arch-specific sections. Return 0 on success. */
......
...@@ -722,28 +722,22 @@ static int obsolete_params(const char *name, ...@@ -722,28 +722,22 @@ static int obsolete_params(const char *name,
} }
#endif /* CONFIG_OBSOLETE_MODPARM */ #endif /* CONFIG_OBSOLETE_MODPARM */
/* Find an symbol for this module (ie. resolve internals first). /* Resolve a symbol for this module. I.e. if we find one, record usage.
It we find one, record usage. Must be holding module_mutex. */ Must be holding module_mutex. */
unsigned long find_symbol_internal(Elf_Shdr *sechdrs, static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
unsigned int symindex, unsigned int symindex,
const char *strtab, const char *strtab,
const char *name, const char *name,
struct module *mod, struct module *mod)
struct kernel_symbol_group **ksg)
{ {
struct kernel_symbol_group *ksg;
unsigned long ret; unsigned long ret;
ret = find_local_symbol(sechdrs, symindex, strtab, name);
if (ret) {
*ksg = NULL;
return ret;
}
/* Look in other modules... */
spin_lock_irq(&modlist_lock); spin_lock_irq(&modlist_lock);
ret = __find_symbol(name, ksg, mod->license_gplok); ret = __find_symbol(name, &ksg, mod->license_gplok);
if (ret) { if (ret) {
/* This can fail due to OOM, or module unloading */ /* This can fail due to OOM, or module unloading */
if (!use_module(mod, (*ksg)->owner)) if (!use_module(mod, ksg->owner))
ret = 0; ret = 0;
} }
spin_unlock_irq(&modlist_lock); spin_unlock_irq(&modlist_lock);
...@@ -832,21 +826,19 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -832,21 +826,19 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
unsigned int strindex, unsigned int strindex,
struct module *mod) struct module *mod)
{ {
unsigned int i; Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
Elf_Sym *sym; const char *strtab = (char *)sechdrs[strindex].sh_addr;
unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
/* First simplify defined symbols, so if they become the int ret = 0;
"answer" to undefined symbols, copying their st_value us
correct. */ for (i = 1; i < n; i++) {
for (sym = (void *)sechdrs[symindex].sh_addr, i = 0;
i < sechdrs[symindex].sh_size / sizeof(Elf_Sym);
i++) {
switch (sym[i].st_shndx) { switch (sym[i].st_shndx) {
case SHN_COMMON: case SHN_COMMON:
/* We compiled with -fno-common. These are not /* We compiled with -fno-common. These are not
supposed to happen. */ supposed to happen. */
DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name); DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name);
return -ENOEXEC; ret = -ENOEXEC;
break;
case SHN_ABS: case SHN_ABS:
/* Don't need to do anything */ /* Don't need to do anything */
...@@ -855,6 +847,20 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -855,6 +847,20 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
break; break;
case SHN_UNDEF: case SHN_UNDEF:
sym[i].st_value
= resolve_symbol(sechdrs, symindex, strtab,
strtab + sym[i].st_name, mod);
/* Ok if resolved. */
if (sym[i].st_value != 0)
break;
/* Ok if weak. */
if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
break;
printk(KERN_WARNING "%s: Unknown symbol %s\n",
mod->name, strtab + sym[i].st_name);
ret = -ENOENT;
break; break;
default: default:
...@@ -862,30 +868,11 @@ static int simplify_symbols(Elf_Shdr *sechdrs, ...@@ -862,30 +868,11 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
= (unsigned long) = (unsigned long)
(sechdrs[sym[i].st_shndx].sh_addr (sechdrs[sym[i].st_shndx].sh_addr
+ sym[i].st_value); + sym[i].st_value);
break;
} }
} }
/* Now try to resolve undefined symbols */ return ret;
for (sym = (void *)sechdrs[symindex].sh_addr, i = 0;
i < sechdrs[symindex].sh_size / sizeof(Elf_Sym);
i++) {
if (sym[i].st_shndx == SHN_UNDEF) {
/* Look for symbol */
struct kernel_symbol_group *ksg = NULL;
const char *strtab
= (char *)sechdrs[strindex].sh_addr;
sym[i].st_value
= find_symbol_internal(sechdrs,
symindex,
strtab,
strtab + sym[i].st_name,
mod,
&ksg);
}
}
return 0;
} }
/* Update size with this section: return offset. */ /* Update size with this section: return offset. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment