vfree(region);
}
-long
-module_core_size(const Elf32_Ehdr *hdr, const Elf32_Shdr *sechdrs,
- const char *secstrings, struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
- return module->core_size;
-}
-
-long
-module_init_size(const Elf32_Ehdr *hdr, const Elf32_Shdr *sechdrs,
- const char *secstrings, struct module *module)
-{
- return module->init_size;
+ return 0;
}
int
}
/* We don't need anything special. */
-long module_core_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
- return module->core_size;
-}
-
-long module_init_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs,
return ret;
}
-long module_core_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(Elf32_Ehdr *hdr,
+ Elf32_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *me)
{
- module->arch.core_plt_offset = ALIGN(module->core_size, 4);
- return module->arch.core_plt_offset
- + get_plt_size(hdr, sechdrs, secstrings, 0);
-}
+ unsigned int i;
-long module_init_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- module->arch.init_plt_offset = ALIGN(module->init_size, 4);
- return module->arch.init_plt_offset
- + get_plt_size(hdr, sechdrs, secstrings, 1);
+ /* Find .plt and .pltinit sections */
+ for (i = 0; i < hdr->e_shnum; i++) {
+ if (strcmp(secstrings + sechdrs[i].sh_name, ".plt.init") == 0)
+ me->arch.init_plt_section = i;
+ else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
+ me->arch.core_plt_section = i;
+ }
+ if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
+ printk("Module doesn't contain .plt or .plt.init sections.\n");
+ return -ENOEXEC;
+ }
+
+ /* Override their sizes */
+ sechdrs[me->arch.core_plt_section].sh_size
+ = get_plt_size(hdr, sechdrs, secstrings, 0);
+ sechdrs[me->arch.init_plt_section].sh_size
+ = get_plt_size(hdr, sechdrs, secstrings, 1);
+ return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs,
}
/* Set up a trampoline in the PLT to bounce us to the distant function */
-static uint32_t do_plt_call(void *location, Elf32_Addr val, struct module *mod)
+static uint32_t do_plt_call(void *location,
+ Elf32_Addr val,
+ Elf32_Shdr *sechdrs,
+ struct module *mod)
{
struct ppc_plt_entry *entry;
DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
/* Init, or core PLT? */
if (location >= mod->module_core
- && location < mod->module_core + mod->arch.core_plt_offset)
- entry = mod->module_core + mod->arch.core_plt_offset;
+ && location < mod->module_core + mod->core_size)
+ entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
else
- entry = mod->module_init + mod->arch.init_plt_offset;
+ entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
/* Find this entry, or if that fails, the next avail. entry */
while (entry->jump[0]) {
case R_PPC_REL24:
if ((int)(value - (uint32_t)location) < -0x02000000
|| (int)(value - (uint32_t)location) >= 0x02000000)
- value = do_plt_call(location, value, module);
+ value = do_plt_call(location, value,
+ sechdrs, module);
/* Only replace bits 2 through 26 */
DEBUGP("REL24 value = %08X. location = %08X\n",
table entries. */
}
-/* s390/s390x needs additional memory for GOT/PLT sections. */
-long module_core_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
// FIXME: add space needed for GOT/PLT
- return module->core_size;
-}
-
-long module_init_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
-
-
int apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
}
/* s390/s390x needs additional memory for GOT/PLT sections. */
-long module_core_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
// FIXME: add space needed for GOT/PLT
- return module->core_size;
-}
-
-long module_init_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
-
-
int apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
}
/* We don't need anything special. */
-long module_core_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
- return module->core_size;
-}
-
-long module_init_size(const Elf32_Ehdr *hdr,
- const Elf32_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs,
}
/* We don't need anything special. */
-long module_core_size(const Elf64_Ehdr *hdr,
- const Elf64_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
- return module->core_size;
-}
-
-long module_init_size(const Elf64_Ehdr *hdr,
- const Elf64_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
int apply_relocate(Elf64_Shdr *sechdrs,
#define DEBUGP(fmt...)
/* We don't need anything special. */
-long module_core_size(const Elf64_Ehdr *hdr,
- const Elf64_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod)
{
- return module->core_size;
-}
-
-long module_init_size(const Elf64_Ehdr *hdr,
- const Elf64_Shdr *sechdrs,
- const char *secstrings,
- struct module *module)
-{
- return module->init_size;
+ return 0;
}
int apply_relocate_add(Elf64_Shdr *sechdrs,
struct mod_arch_specific
{
- /* How much of the core is actually taken up with core (then
- we know the rest is for the PLT */
- unsigned int core_plt_offset;
-
- /* Same for init */
- unsigned int init_plt_offset;
+ /* Indices of PLT sections within module. */
+ unsigned int core_plt_section, init_plt_section;
};
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+/* Make empty sections for module_frob_arch_sections to expand. */
+#ifdef MODULE
+asm(".section .plt,\"aws\",@nobits; .align 3; .previous");
+asm(".section .plt.init,\"aws\",@nobits; .align 3; .previous");
+#endif
#endif /* _ASM_PPC_MODULE_H */
/* These must be implemented by the specific architecture */
-/* Total size to allocate for the non-releasable code; return len or
- -error. mod->core_size is the current generic tally. */
-long module_core_size(const Elf_Ehdr *hdr,
- const Elf_Shdr *sechdrs,
- const char *secstrings,
- struct module *mod);
-
-/* Total size of (if any) sections to be freed after init. Return 0
- for none, len, or -error. mod->init_size is the current generic
- tally. */
-long module_init_size(const Elf_Ehdr *hdr,
- const Elf_Shdr *sechdrs,
- const char *secstrings,
- struct module *mod);
+/* Adjust arch-specific sections. Return 0 on success. */
+int module_frob_arch_sections(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ const char *secstrings,
+ struct module *mod);
/* Allocator used for allocating struct module, core sections and init
sections. Returns NULL on failure. */
/* Rewritten by Rusty Russell, on the backs of many others...
+ Copyright (C) 2002 Richard Henderson
Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
This program is free software; you can redistribute it and/or modify
#include <linux/rcupdate.h>
#include <linux/cpu.h>
#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/err.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/pgalloc.h>
#define DEBUGP(fmt , a...)
#endif
+#ifndef ARCH_SHF_SMALL
+#define ARCH_SHF_SMALL 0
+#endif
+
+/* If this is set, the section belongs in the init part of the module */
+#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
+
#define symbol_is(literal, string) \
(strcmp(MODULE_SYMBOL_PREFIX literal, (string)) == 0)
return try_module_get(mod);
}
-/* Convenient structure for holding init and core sizes */
-struct sizes
-{
- unsigned long init_size;
- unsigned long core_size;
-};
-
/* Stub function for modules which don't have an initfn */
int init_module(void)
{
}
EXPORT_SYMBOL_GPL(__symbol_get);
-/* Transfer one ELF section to the correct (init or core) area. */
-static void *copy_section(const char *name,
- void *base,
- Elf_Shdr *sechdr,
- struct module *mod,
- struct sizes *used)
-{
- void *dest;
- unsigned long *use;
- unsigned long max;
-
- /* Only copy to init section if there is one */
- if (strstr(name, ".init") && mod->module_init) {
- dest = mod->module_init;
- use = &used->init_size;
- max = mod->init_size;
- } else {
- dest = mod->module_core;
- use = &used->core_size;
- max = mod->core_size;
- }
-
- /* Align up */
- *use = ALIGN(*use, sechdr->sh_addralign);
- dest += *use;
- *use += sechdr->sh_size;
-
- if (*use > max)
- return ERR_PTR(-ENOEXEC);
-
- /* May not actually be in the file (eg. bss). */
- if (sechdr->sh_type != SHT_NOBITS)
- memcpy(dest, base + sechdr->sh_offset, sechdr->sh_size);
-
- return dest;
-}
-
/* Deal with the given section */
static int handle_section(const char *name,
Elf_Shdr *sechdrs,
return 0;
}
-/* Get the total allocation size of the init and non-init sections */
-static struct sizes get_sizes(const Elf_Ehdr *hdr,
- const Elf_Shdr *sechdrs,
- const char *secstrings)
+/* Update size with this section: return offset. */
+static long get_offset(unsigned long *size, Elf_Shdr *sechdr)
{
- struct sizes ret = { 0, 0 };
- unsigned i;
-
- /* Everything marked ALLOC (this includes the exported
- symbols) */
- for (i = 1; i < hdr->e_shnum; i++) {
- unsigned long *add;
+ long ret;
- /* If it's called *.init*, and we're init, we're interested */
- if (strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
- add = &ret.init_size;
- else
- add = &ret.core_size;
+ ret = ALIGN(*size, sechdr->sh_addralign ?: 1);
+ *size = ret + sechdr->sh_size;
+ return ret;
+}
- if (sechdrs[i].sh_flags & SHF_ALLOC) {
- /* Pad up to required alignment */
- *add = ALIGN(*add, sechdrs[i].sh_addralign ?: 1);
- *add += sechdrs[i].sh_size;
+/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
+ might -- code, read-only data, read-write data, small data. Tally
+ sizes, and place the offsets into sh_link fields: high bit means it
+ belongs in init. */
+static void layout_sections(struct module *mod,
+ const Elf_Ehdr *hdr,
+ Elf_Shdr *sechdrs,
+ const char *secstrings)
+{
+ static unsigned long const masks[][2] = {
+ { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
+ { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
+ { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
+ { ARCH_SHF_SMALL | SHF_ALLOC, 0 }
+ };
+ unsigned int m, i;
+
+ for (i = 0; i < hdr->e_shnum; i++)
+ sechdrs[i].sh_link = ~0UL;
+
+ DEBUGP("Core section allocation order:\n");
+ for (m = 0; m < ARRAY_SIZE(masks); ++m) {
+ for (i = 0; i < hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &sechdrs[i];
+
+ if ((s->sh_flags & masks[m][0]) != masks[m][0]
+ || (s->sh_flags & masks[m][1])
+ || s->sh_link != ~0UL
+ || strstr(secstrings + s->sh_name, ".init"))
+ continue;
+ s->sh_link = get_offset(&mod->core_size, s);
+ DEBUGP("\t%s\n", name);
}
}
- return ret;
+ DEBUGP("Init section allocation order:\n");
+ for (m = 0; m < ARRAY_SIZE(masks); ++m) {
+ for (i = 0; i < hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &sechdrs[i];
+
+ if ((s->sh_flags & masks[m][0]) != masks[m][0]
+ || (s->sh_flags & masks[m][1])
+ || s->sh_link != ~0UL
+ || !strstr(secstrings + s->sh_name, ".init"))
+ continue;
+ s->sh_link = (get_offset(&mod->init_size, s)
+ | INIT_OFFSET_MASK);
+ DEBUGP("\t%s\n", name);
+ }
+ }
}
/* Allocate and load the module */
unsigned int i, symindex, exportindex, strindex, setupindex, exindex,
modindex, obsparmindex;
long arglen;
- struct sizes sizes, used;
struct module *mod;
long err = 0;
void *ptr = NULL; /* Stops spurious gcc uninitialized warning */
mod->state = MODULE_STATE_COMING;
- /* How much space will we need? */
- sizes = get_sizes(hdr, sechdrs, secstrings);
-
- /* Set these up, and allow archs to manipulate them. */
- mod->core_size = sizes.core_size;
- mod->init_size = sizes.init_size;
-
- /* Allow archs to add to them. */
- err = module_init_size(hdr, sechdrs, secstrings, mod);
+ /* Allow arches to frob section contents and sizes. */
+ err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
if (err < 0)
goto free_mod;
- mod->init_size = err;
- err = module_core_size(hdr, sechdrs, secstrings, mod);
- if (err < 0)
- goto free_mod;
- mod->core_size = err;
+ /* Determine total sizes, and put offsets in sh_link. For now
+ this is done generically; there doesn't appear to be any
+ special cases for the architectures. */
+ layout_sections(mod, hdr, sechdrs, secstrings);
/* Do the allocs. */
ptr = module_alloc(mod->core_size);
memset(ptr, 0, mod->init_size);
mod->module_init = ptr;
- /* Transfer each section which requires ALLOC, and set sh_addr
- fields to absolute addresses. */
- used.core_size = 0;
- used.init_size = 0;
- for (i = 1; i < hdr->e_shnum; i++) {
- if (sechdrs[i].sh_flags & SHF_ALLOC) {
- ptr = copy_section(secstrings + sechdrs[i].sh_name,
- hdr, &sechdrs[i], mod, &used);
- if (IS_ERR(ptr))
- goto cleanup;
- sechdrs[i].sh_addr = (unsigned long)ptr;
- /* Have we just copied __this_module across? */
- if (i == modindex)
- mod = ptr;
- }
+ /* Transfer each section which specifies SHF_ALLOC */
+ for (i = 0; i < hdr->e_shnum; i++) {
+ void *dest;
+
+ if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ continue;
+
+ if (sechdrs[i].sh_link & INIT_OFFSET_MASK)
+ dest = mod->module_init
+ + (sechdrs[i].sh_link & ~INIT_OFFSET_MASK);
+ else
+ dest = mod->module_core + sechdrs[i].sh_link;
+
+ if (sechdrs[i].sh_type != SHT_NOBITS)
+ memcpy(dest, (void *)sechdrs[i].sh_addr,
+ sechdrs[i].sh_size);
+ /* Update sh_addr to point to copy in image. */
+ sechdrs[i].sh_addr = (unsigned long)dest;
}
- /* Don't use more than we allocated! */
- if (used.init_size > mod->init_size || used.core_size > mod->core_size)
- BUG();
+ /* Module has been moved. */
+ mod = (void *)sechdrs[modindex].sh_addr;
/* Now we've moved module, initialize linked lists, etc. */
module_unload_init(mod);