Support really large LKMs. Find out how much space is needed for symbols

and then allocate it on demand.  Rename some common symbols (__bss_start,
_edata, _end, __start_link_set_*, __stop_link_set_*) so that ".<module>"
is appended to them.  This shrinks an amd64 kernel by 20KB of BSS.
This commit is contained in:
matt 2004-02-18 23:44:49 +00:00
parent 074a9e8fee
commit f01501b2c6
2 changed files with 112 additions and 41 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_ksyms.c,v 1.19 2004/02/18 20:41:09 matt Exp $ */
/* $NetBSD: kern_ksyms.c,v 1.20 2004/02/18 23:44:49 matt Exp $ */
/*
* Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.19 2004/02/18 20:41:09 matt Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.20 2004/02/18 23:44:49 matt Exp $");
#ifdef _KERNEL
#include "opt_ddb.h"
@ -604,43 +604,62 @@ ksyms_sizes_calc(void)
#endif
/*
* Temporary work buffers for dynamic loaded symbol tables.
* Temporary work structure for dynamic loaded symbol tables.
* Will go away when in-kernel linker is in place.
*/
#define NSAVEDSYMS 512
#define SZSYMNAMES NSAVEDSYMS*8 /* Just an approximation */
static Elf_Sym savedsyms[NSAVEDSYMS];
static int symnmoff[NSAVEDSYMS];
static char symnames[SZSYMNAMES];
static int cursyms, curnamep;
struct syminfo {
size_t cursyms;
size_t curnamep;
size_t maxsyms;
size_t maxnamep;
Elf_Sym *syms;
int *symnmoff;
char *symnames;
};
/*
* Add a symbol to the temporary save area for symbols.
* This routine will go away when the in-kernel linker is in place.
*/
static void
addsym(Elf_Sym *sym, char *name)
addsym(struct syminfo *info, const Elf_Sym *sym, const char *name,
const char *mod)
{
int len;
int len, mlen;
#ifdef KSYMS_DEBUG
if (ksyms_debug & FOLLOW_MORE_CALLS)
printf("addsym: name %s val %lx\n", name, (long)sym->st_value);
#endif
if (cursyms == NSAVEDSYMS ||
((len = strlen(name) + 1) + curnamep) > SZSYMNAMES) {
len = strlen(name) + 1;
if (mod)
mlen = 1 + strlen(mod);
else
mlen = 0;
if (info->cursyms == info->maxsyms ||
(len + mlen + info->curnamep) > info->maxnamep) {
printf("addsym: too many symbols, skipping '%s'\n", name);
return;
}
strlcpy(&symnames[curnamep], name, sizeof(symnames) - curnamep);
savedsyms[cursyms] = *sym;
symnmoff[cursyms] = savedsyms[cursyms].st_name = curnamep;
curnamep += len;
strlcpy(&info->symnames[info->curnamep], name,
info->maxnamep - info->curnamep);
if (mlen) {
info->symnames[info->curnamep + len - 1] = '.';
strlcpy(&info->symnames[info->curnamep + len], mod,
info->maxnamep - (info->curnamep + len));
len += mlen;
}
info->syms[info->cursyms] = *sym;
info->syms[info->cursyms].st_name = info->curnamep;
info->symnmoff[info->cursyms] = info->curnamep;
info->curnamep += len;
#if NKSYMS
if (len > ksyms_maxlen)
ksyms_maxlen = len;
#endif
cursyms++;
info->cursyms++;
}
/*
* Adds a symbol table.
@ -657,7 +676,8 @@ ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
struct symtab *st;
unsigned long rval;
int i;
char *str, *name;
char *name;
struct syminfo info;
#ifdef KSYMS_DEBUG
if (ksyms_debug & FOLLOW_CALLS)
@ -683,10 +703,11 @@ ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
/*
* XXX - Only add a symbol if it do not exist already.
* This is because of a flaw in the current LKM implementation,
* the loop will be removed once the in-kernel linker is in place.
* these loops will be removed once the in-kernel linker is in place.
*/
cursyms = curnamep = 0;
memset(&info, 0, sizeof(info));
for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
char * const symname = strstart + sym[i].st_name;
if (sym[i].st_name == 0)
continue; /* Just ignore */
@ -696,36 +717,80 @@ ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
continue;
/* Check if the symbol exists */
if (ksyms_getval_from_kernel(NULL, strstart + sym[i].st_name,
if (ksyms_getval_from_kernel(NULL, symname,
&rval, KSYMS_EXTERN) == 0) {
/* Check (and complain) about differing values */
if (sym[i].st_value != rval) {
printf("%s: symbol '%s' redeclared with "
"different value (%lx != %lx)\n",
mod, strstart + sym[i].st_name,
rval, (long)sym[i].st_value);
if (!strcmp(symname, "__bss_start") ||
!strcmp(symname, "_edata") ||
!strcmp(symname, "_end") ||
!strncmp(symname, "__start_link_set_",17) ||
!strncmp(symname, "__stop_link_set_",16)) {
info.maxsyms++;
info.maxnamep += strlen(symname) + 1 +
strlen(mod) + 1;
} else {
printf("%s: symbol '%s' redeclared with"
" different value (%lx != %lx)\n",
mod, symname,
rval, (long)sym[i].st_value);
}
}
} else {
/*
* Count this symbol
*/
info.maxsyms++;
info.maxnamep += strlen(symname) + 1;
}
}
/*
* Now that we know the sizes, malloc the structures.
*/
info.syms = malloc(sizeof(Elf_Sym)*info.maxsyms, M_DEVBUF, M_WAITOK);
info.symnames = malloc(info.maxnamep, M_DEVBUF, M_WAITOK);
info.symnmoff = malloc(sizeof(int)*info.maxsyms, M_DEVBUF, M_WAITOK);
/*
* Now that we have the symbols, actually fill in the structures.
*/
for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
char * const symname = strstart + sym[i].st_name;
if (sym[i].st_name == 0)
continue; /* Just ignore */
/* check validity of the symbol */
/* XXX - save local symbols if DDB */
if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
continue;
/* Check if the symbol exists */
if (ksyms_getval_from_kernel(NULL, symname,
&rval, KSYMS_EXTERN) == 0) {
if ((sym[i].st_value != rval) &&
(!strcmp(symname, "__bss_start") ||
!strcmp(symname, "_edata") ||
!strcmp(symname, "_end") ||
!strncmp(symname, "__start_link_set_",17) ||
!strncmp(symname, "__stop_link_set_",16))) {
addsym(&info, &sym[i], symname, mod);
}
} else
/* Ok, save this symbol */
addsym(&sym[i], strstart + sym[i].st_name);
addsym(&info, &sym[i], symname, NULL);
}
sym = malloc(sizeof(Elf_Sym)*cursyms, M_DEVBUF, M_WAITOK);
str = malloc(curnamep, M_DEVBUF, M_WAITOK);
memcpy(sym, savedsyms, sizeof(Elf_Sym)*cursyms);
memcpy(str, symnames, curnamep);
st = malloc(sizeof(struct symtab), M_DEVBUF, M_WAITOK);
i = strlen(mod) + 1;
name = malloc(i, M_DEVBUF, M_WAITOK);
strlcpy(name, mod, i);
st->sd_name = name;
st->sd_symnmoff = malloc(sizeof(int)*cursyms, M_DEVBUF, M_WAITOK);
memcpy(st->sd_symnmoff, symnmoff, sizeof(int)*cursyms);
st->sd_symstart = sym;
st->sd_symsize = sizeof(Elf_Sym)*cursyms;
st->sd_strstart = str;
st->sd_strsize = curnamep;
st->sd_symnmoff = info.symnmoff;
st->sd_symstart = info.syms;
st->sd_symsize = sizeof(Elf_Sym)*info.maxsyms;
st->sd_strstart = info.symnames;
st->sd_strsize = info.maxnamep;
/* Make them absolute references */
sym = st->sd_symstart;

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lkm.c,v 1.70 2003/11/17 10:16:18 cube Exp $ */
/* $NetBSD: kern_lkm.c,v 1.71 2004/02/18 23:44:49 matt Exp $ */
/*
* Copyright (c) 1994 Christopher G. Demetriou
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lkm.c,v 1.70 2003/11/17 10:16:18 cube Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lkm.c,v 1.71 2004/02/18 23:44:49 matt Exp $");
#include "opt_ddb.h"
#include "opt_malloclog.h"
@ -431,7 +431,13 @@ lkmioctl(dev, cmd, data, flag, p)
/* call entry(load)... (assigns "private" portion) */
error = (*(curp->entry))(curp, LKM_E_LOAD, LKM_VERSION);
(void)ksyms_rensymtab("/lkmtemp/", curp->private.lkm_any->lkm_name);
if (curp->syms && curp->sym_offset >= curp->sym_size) {
ksyms_delsymtab("/lkmtemp/");
error = ksyms_addsymtab(curp->private.lkm_any->lkm_name,
(char *)curp->syms, curp->sym_symsize,
(char *)curp->syms + curp->sym_symsize,
curp->sym_size - curp->sym_symsize);
}
if (error) {
/*
* Module may refuse loading or may have a