Name: Small Common Section Handling Author: Rusty Russell Status: Untested D: Richard Henderson points out that some archs need to make sure that small D: symbols are within reach of the GOT/GP pointer. This is part of D: the solution (the other is to allow archs to reorder sections at load D: time). diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.5.52/kernel/module.c working-2.5.52-common/kernel/module.c --- linux-2.5.52/kernel/module.c 2002-12-17 08:11:03.000000000 +1100 +++ working-2.5.52-common/kernel/module.c 2002-12-26 15:25:00.000000000 +1100 @@ -38,6 +38,12 @@ #define DEBUGP(fmt , a...) #endif +/* You must be below this line to be considered small, and hence + closest to start of module. */ +#ifndef MODULE_SMALL_COMMON_SIZE +#define MODULE_SMALL_COMMON_SIZE 0 +#endif + #define symbol_is(literal, string) \ (strcmp(MODULE_SYMBOL_PREFIX literal, (string)) == 0) @@ -834,12 +840,13 @@ static int handle_section(const char *na } /* Figure out total size desired for the common vars */ -static unsigned long read_commons(void *start, Elf_Shdr *sechdr) +static unsigned long read_commons(void *start, Elf_Shdr *sechdr, + unsigned long *scommon_offset) { - unsigned long size, i, max_align; + unsigned long bsize, ssize, i, max_align; Elf_Sym *sym; - size = max_align = 0; + size = ssize = max_align = 0; for (sym = start + sechdr->sh_offset, i = 0; i < sechdr->sh_size / sizeof(Elf_Sym); @@ -848,15 +855,23 @@ static unsigned long read_commons(void * /* Value encodes alignment. */ if (sym[i].st_value > max_align) max_align = sym[i].st_value; - /* Pad to required alignment */ - size = ALIGN(size, sym[i].st_value) + sym[i].st_size; + + if (sym[i].st_size >= MODULE_SMALL_COMMON_SIZE) + /* Big section: pad to required alignment */ + bsize = ALIGN(bsize, sym[i].st_value) + + sym[i].st_size; + else /* Small section. */ + ssize = ALIGN(ssize, sym[i].st_value) + + sym[i].st_size; } } + *scommon_offset = bsize; + /* Now, add in max alignment requirement (with align attribute, this could be large), so we know we have space whatever the start alignment is */ - return size + max_align; + return bsize + ssize + max_align; } /* Change all symbols so that sh_value encodes the pointer directly. */ @@ -864,6 +879,7 @@ static void simplify_symbols(Elf_Shdr *s unsigned int symindex, unsigned int strindex, void *common, + void *scommon, struct module *mod) { unsigned int i; @@ -877,14 +893,20 @@ static void simplify_symbols(Elf_Shdr *s i++) { switch (sym[i].st_shndx) { case SHN_COMMON: - /* Value encodes alignment. */ - common = (void *)ALIGN((unsigned long)common, - sym[i].st_value); - /* Change it to encode pointer */ - sym[i].st_value = (unsigned long)common; - common += sym[i].st_size; + if (sym[i].st_size >= MODULE_SMALL_COMMON_SIZE) { + /* Value encodes alignment. */ + common = (void *)ALIGN((unsigned long)common, + sym[i].st_value); + /* Change it to encode pointer */ + sym[i].st_value = (unsigned long)common; + common += sym[i].st_size; + } else { + scommon = (void *)ALIGN((unsigned long)scommon, + sym[i].st_value); + sym[i].st_value = (unsigned long)scommon; + scommon += sym[i].st_size; + } break; - case SHN_ABS: /* Don't need to do anything */ DEBUGP("Absolute symbol: 0x%08lx\n", @@ -967,7 +989,7 @@ static struct module *load_module(void * unsigned int i, symindex, exportindex, strindex, setupindex, exindex, modnameindex, obsparmindex; long arglen; - unsigned long common_length; + unsigned long common_length, scommon_offset; struct sizes sizes, used; struct module *mod; long err = 0; @@ -1092,7 +1114,7 @@ static struct module *load_module(void * module_unload_init(mod); /* How much space will we need? (Common area in first) */ - common_length = read_commons(hdr, &sechdrs[symindex]); + common_length = read_commons(hdr, &sechdrs[symindex], &scommon_offset); sizes = get_sizes(hdr, sechdrs, secstrings, common_length); /* Set these up, and allow archs to manipulate them. */ @@ -1147,7 +1169,8 @@ static struct module *load_module(void * BUG(); /* Fix up syms, so that st_value is a pointer to location. */ - simplify_symbols(sechdrs, symindex, strindex, mod->module_core, mod); + simplify_symbols(sechdrs, symindex, strindex, mod->module_core, + mod->module_core + scommon_offset, mod); /* Set up EXPORTed symbols */ if (exportindex) {