Commit e8253652 authored by Tony Luck's avatar Tony Luck Committed by David Mosberger

[PATCH] ia64: fix reloc-out-of-range error on module loading

I'm hitting this problem because the module I want to load was
compiled with -g, so the filesize is absolutely huge.  kernel/module.c
does a vmalloc() to inhale the entire file, and then two calls to
module_alloc() (which calls vmalloc() on ia64) to load the 'init' and
'core' sections. The 'init' is small and slips into a gap early in the
vmalloc playspace, while the 'core' area is allocated after the huge
area that was allocated for the inhaled copy of the whole file.

I made a one coding change to Jean-Marc's version, adding a check to
see whether the init/core sections are close enough together for the
PCREL21B to reach (they almost always are).

I've kept the test that there are no jumps from core to init (though
the message that is printed is almost as unhelpful as the one that you
get when you statically link a module into the kernel that has calls
to the discarded .exit section :-)

This patch stalled out before on the question of whether a PLT was
overkill for a section-to-section branch, and whether it would be
better to use relaxation techniques to extend the range.  Doing that
might be more elegant in some way, but it needs a whole heap of extra
code (to count how many relaxed branches need to be added and
allocated them as needed).  This seems a lot of extra code that is
only ever going to be exercised by maniacs like me with 49MB .ko
files.

I fixed up the comments to be a little more heplful.

Signed-off-by: <tony.luck@intel.com>
Signed-off-by: default avatarDavid Mosberger <davidm@hpl.hp.com>
parent 3982a1ad
...@@ -656,8 +656,26 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, ...@@ -656,8 +656,26 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend,
case RV_PCREL: case RV_PCREL:
switch (r_type) { switch (r_type) {
case R_IA64_PCREL21B: case R_IA64_PCREL21B:
/* special because it can cross into other module/kernel-core. */ if (in_init(mod, val)) {
if (!is_internal(mod, val)) /* Calls to init code from core are bad news */
if (in_core(mod, (uint64_t)location)) {
printk(KERN_ERR "%s: init symbol 0x%lx used in module code at %p\n",
mod->name, val, location);
return -ENOEXEC;
}
} else if (in_core(mod, val)) {
/*
* Init section may have been allocated far away from core,
* if the branch won't reach, then allocate a plt for it.
*/
if (in_init(mod, (uint64_t)location)) {
uint64_t delta = ((int64_t)val - (int64_t)location) / 16;
if (delta + (1 << 20) >= (1 << 21)) {
val = get_fdesc(mod, val, &ok);
val = get_plt(mod, location, val, &ok);
}
}
} else
val = get_plt(mod, location, val, &ok); val = get_plt(mod, location, val, &ok);
/* FALL THROUGH */ /* FALL THROUGH */
default: default:
......
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