add ELF support, mostly from joda@pdc.kth.se (Johan Danielsson) in PR#6149,

updated for the symtab support for a.out (non for ELF yet) and other cleanup
by myself.  should work on the alpha as well as other ELF ports...
remove the ld(1) output by default, rather than leaving little binary turds
across the filesystem...
This commit is contained in:
mrg 1999-06-13 12:54:40 +00:00
parent f90f079222
commit 72a64c5437
6 changed files with 801 additions and 227 deletions

View File

@ -1,40 +1,17 @@
# $NetBSD: Makefile,v 1.6 1995/03/18 14:56:41 cgd Exp $
#
# Makefile for modload
#
# 25 May 93 Terry Lambert Original
#
# Copyright (c) 1993 Terrence R. Lambert.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by Terrence R. Lambert.
# 4. The name Terrence R. Lambert may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# $NetBSD: Makefile,v 1.7 1999/06/13 12:54:40 mrg Exp $
WARNS= 1
PROG= modload
SRCS= modload.c
MAN= modload.8
.include <bsd.own.mk> # for OBJECT_FMT
.if (${OBJECT_FMT} == "ELF")
SRCS+= elf.c
.else
SRCS+= a.out.c
CFLAGS+=-DUSE_AOUT
.endif
.include <bsd.prog.mk>

256
sbin/modload/a.out.c Normal file
View File

@ -0,0 +1,256 @@
/* $NetBSD: a.out.c,v 1.1 1999/06/13 12:54:40 mrg Exp $ */
/*
* Copyright (c) 1993 Terrence R. Lambert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: a.out.c,v 1.1 1999/06/13 12:54:40 mrg Exp $");
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/lkm.h>
#include <a.out.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "modload.h"
/*
* Expected linker options:
*
* -A executable to link against
* -e entry point
* -o output file
* -T address to link to in hex (assumes it's a page boundry)
* <target> object file
*/
#define LINKCMD "ld -A %s -e _%s -o %s -T %p %s"
void
a_out_linkcmd(char *buf,
size_t len,
const char *kernel,
const char *entry,
const char *outfile,
const void *address,
const char *object)
{
ssize_t n;
n = snprintf(buf, len, LINKCMD, kernel, entry,
outfile, address, object);
if (n >= len)
errx(1, "link command longer than %lu bytes", (u_long)len);
}
static int
a_out_read_header(int fd, struct exec *info_buf)
{
ssize_t n;
n = read(fd, info_buf, sizeof(*info_buf));
if (n < 0)
err(1, "failed reading %lu bytes", (u_long)sizeof(*info_buf));
if (n != sizeof(*info_buf)) {
if (debug)
fprintf(stderr, "failed to read %lu bytes",
(u_long)sizeof(*info_buf));
return -1;
}
/*
* Magic number...
*/
if (N_BADMAG(*info_buf))
errx(4, "not an a.out format file");
return 0;
}
extern int symtab;
int
a_out_mod_sizes(fd, modsize, strtablen, resrvp, sp)
int fd;
size_t *modsize;
int *strtablen;
struct lmc_resrv *resrvp;
struct stat *sp;
{
struct exec info_buf;
if (a_out_read_header(fd, &info_buf) < 0)
return -1;
/*
* Calculate the size of the module
*/
*modsize = info_buf.a_text + info_buf.a_data + info_buf.a_bss;
*strtablen = sp->st_size - N_STROFF(info_buf);
if (symtab) {
/*
* XXX TODO: grovel through symbol table looking for
* just the symbol table stuff from the new module,
* and skip the stuff from the kernel.
*/
resrvp->sym_size = info_buf.a_syms + *strtablen;
resrvp->sym_symsize = info_buf.a_syms;
} else
resrvp->sym_size = resrvp->sym_symsize = 0;
return (0);
}
void *
a_out_mod_load(int fd)
{
struct exec info_buf;
size_t b;
ssize_t n;
char buf[10 * BUFSIZ];
/*
* Get the load module post load size... do this by reading the
* header and doing page counts.
*/
if (a_out_read_header(fd, &info_buf) < 0)
return NULL;
/*
* Seek to the text offset to start loading...
*/
if (lseek(fd, N_TXTOFF(info_buf), 0) == -1)
err(12, "lseek");
/*
* Transfer the relinked module to kernel memory in chunks of
* MODIOBUF size at a time.
*/
b = info_buf.a_text + info_buf.a_data;
while (b) {
n = read(fd, buf, MIN(b, sizeof(buf)));
if (n < 0)
err(1, "while reading from prelinked module");
if (n == 0)
errx(1, "EOF while reading from prelinked module");
loadbuf(buf, n);
b -= n;
}
return (void*)info_buf.a_entry;
}
extern int devfd, modfd;
extern struct lmc_resrv resrv;
void
a_out_mod_symload(strtablen)
int strtablen;
{
struct exec info_buf;
struct lmc_loadbuf ldbuf;
struct nlist *nlp;
char buf[10 * BUFSIZ];
char *symbuf;
int bytesleft, sz;
int numsyms; /* XXX unused? */
if (a_out_read_header(modfd, &info_buf) < 0)
return;
/*
* Seek to the symbol table to start loading it...
*/
if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1)
err(12, "lseek");
/*
* Transfer the symbol table entries. First, read them all in,
* then adjust their string table pointers, then
* copy in bulk. Then copy the string table itself.
*/
symbuf = malloc(info_buf.a_syms);
if (symbuf == 0)
err(13, "malloc");
if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms)
err(14, "read");
numsyms = info_buf.a_syms / sizeof(struct nlist);
for (nlp = (struct nlist *)symbuf;
(char *)nlp < symbuf + info_buf.a_syms; nlp++) {
register int strx;
strx = nlp->n_un.n_strx;
if (strx != 0) {
/*
* If a valid name, set the name ptr to point at the
* loaded address for the string in the string table.
*/
if (strx > strtablen)
nlp->n_un.n_name = 0;
else
nlp->n_un.n_name = (char *)(strx +
resrv.sym_addr + info_buf.a_syms);
}
}
/*
* we've fixed the symbol table entries, now load them
*/
for (bytesleft = info_buf.a_syms; bytesleft > 0; bytesleft -= sz) {
sz = MIN(bytesleft, MODIOBUF);
ldbuf.cnt = sz;
ldbuf.data = symbuf;
if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
err(11, "error transferring sym buffer");
symbuf += sz;
}
free(symbuf - info_buf.a_syms);
/* and now read the string table and load it. */
for (bytesleft = strtablen; bytesleft > 0; bytesleft -= sz) {
sz = MIN(bytesleft, MODIOBUF);
read(modfd, buf, sz);
ldbuf.cnt = sz;
ldbuf.data = buf;
if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
err(11, "error transferring stringtable buffer");
}
}

341
sbin/modload/elf.c Normal file
View File

@ -0,0 +1,341 @@
/* $NetBSD: elf.c,v 1.1 1999/06/13 12:54:40 mrg Exp $ */
/*
* Copyright (c) 1998 Johan Danielsson <joda@pdc.kth.se>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: elf.c,v 1.1 1999/06/13 12:54:40 mrg Exp $");
#include <sys/param.h>
#if defined(__alpha__) || defined(__arch64__)
#define ELFSIZE 64
#else
#define ELFSIZE 32
#endif
#include <sys/exec_elf.h>
#ifndef ELF_HDR_SIZE
#define ELF_HDR_SIZE sizeof(Elf_Ehdr)
#endif
#include <sys/lkm.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "modload.h"
static void
read_section_header(int fd, Elf_Ehdr *ehdr, int num, Elf_Shdr *shdr)
{
if (lseek(fd, ehdr->e_shoff + num * ehdr->e_shentsize, SEEK_SET) < 0)
err(1, "lseek");
if (read(fd, shdr, sizeof(*shdr)) != sizeof(*shdr))
err(1, "read");
}
struct elf_section {
char *name; /* name of section; points into string table */
enum Elf_s_sht type; /* type of section */
void *addr; /* load address of section */
off_t offset; /* offset in file */
size_t size; /* size of section */
size_t align;
struct elf_section *next;
};
/* adds the section `s' at the correct (sorted by address) place in
the list ponted to by head; *head may be NULL */
static void
add_section(struct elf_section **head, struct elf_section *s)
{
struct elf_section *p, **q;
q = head;
p = *head;
while (1) {
if (p == NULL || p->addr > s->addr) {
s->next = p;
*q = s;
return;
}
q = &p->next;
p = p->next;
}
}
/* make a linked list of all sections containing ALLOCatable data */
static void
read_sections(int fd, Elf_Ehdr *ehdr, char *strtab, struct elf_section **head)
{
int i;
Elf_Shdr shdr;
*head = NULL;
/* scan through section headers */
for (i = 0; i < ehdr->e_shnum; i++) {
struct elf_section *s;
read_section_header(fd, ehdr, i, &shdr);
if ((shdr.sh_flags & SHF_ALLOC) == 0)
/* skip non-ALLOC sections */
continue;
s = malloc(sizeof(*s));
if (s == NULL)
errx(1, "failed to allocate %lu bytes", (u_long)sizeof(*s));
s->name = strtab + shdr.sh_name;
s->type = shdr.sh_type;
s->addr = (void*)shdr.sh_addr;
s->offset = shdr.sh_offset;
s->size = shdr.sh_size;
s->align = shdr.sh_addralign;
add_section(head, s);
}
}
/* free a list of section headers */
static void
free_sections(struct elf_section *head)
{
while (head) {
struct elf_section *p = head;
head = head->next;
free(p);
}
}
/* read string table */
static char *
read_string_table(int fd, Elf_Ehdr *ehdr)
{
Elf_Shdr shdr;
char *strtab;
read_section_header(fd, ehdr, ehdr->e_shstrndx, &shdr);
strtab = malloc(shdr.sh_size);
if (strtab == NULL)
errx(1, "failed to allocate %lu bytes", (u_long)shdr.sh_size);
if (lseek(fd, shdr.sh_offset, SEEK_SET) < 0)
err(1, "lseek");
if (read(fd, strtab, shdr.sh_size) != shdr.sh_size)
err(1, "read");
return strtab;
}
static int
read_elf_header(int fd, Elf_Ehdr *ehdr)
{
ssize_t n;
n = read(fd, ehdr, sizeof(*ehdr));
if (n < 0)
err(1, "failed reading %lu bytes", (u_long)sizeof(*ehdr));
if (n != sizeof(*ehdr)) {
if (debug)
warnx("failed to read %lu bytes", (u_long)sizeof(*ehdr));
return -1;
}
if (memcmp(ehdr->e_ident, Elf_e_ident, Elf_e_siz) != 0)
errx(4, "not in ELF%u format", ELFSIZE);
if (ehdr->e_ehsize != ELF_HDR_SIZE)
errx(4, "file has ELF%u identity, but wrong header size",
ELFSIZE);
return 0;
}
/* offset of data segment; this is horrible, but keeps the size of the
module to a minimum */
static ssize_t data_offset;
/* return size needed by the module */
int
elf_mod_sizes(fd, modsize, strtablen, resrvp, sp)
int fd;
size_t *modsize;
int *strtablen;
struct lmc_resrv *resrvp;
struct stat *sp;
{
Elf_Ehdr ehdr;
ssize_t off = 0;
size_t data_hole = 0;
char *strtab;
struct elf_section *head, *s;
if (read_elf_header(fd, &ehdr) < 0)
return -1;
strtab = read_string_table(fd, &ehdr);
read_sections(fd, &ehdr, strtab, &head);
for (s = head; s && s->next; s = s->next) {
if (debug)
fprintf(stderr,
"%s: addr = %p size = %#lx align = %#lx\n",
s->name, s->addr, (u_long)s->size, (u_long)s->align);
/* XXX try to get rid of the hole before the data
section that GNU-ld likes to put there */
if (strcmp(s->name, ".data") == 0 && s->addr > (void*)off) {
if (debug)
fprintf(stderr, ".data section forced to "
"offset %p (was %p)\n",
(void*)off,
s->addr);
data_offset = off;
/* later remove size of compressed hole from off */
data_hole = (ssize_t)s->addr - off;
}
off = (ssize_t)s->addr + s->size;
}
off -= data_hole;
/* cleanup */
free_sections(head);
free(strtab);
/* XXX round to pagesize? */
#define ROUND(V, S) (((V) + (S) - 1) & ~((S) - 1))
*modsize = ROUND(off, sysconf(_SC_PAGESIZE));
/*
* XXX no symbol table support
*/
*strtablen = 0;
resrvp->sym_size = resrvp->sym_symsize = 0;
return (0);
}
/*
* Expected linker options:
*
* -R executable to link against
* -e entry point
* -o output file
* -Ttext address to link text segment to in hex (assumes it's
* a page boundry)
* -Tdata address to link data segment to in hex
* <target> object file */
#define LINKCMD "ld -R %s -e %s -o %s -Ttext %p %s"
#define LINKCMD2 "ld -R %s -e %s -o %s -Ttext %p -Tdata %p %s"
/* make a link command; XXX if data_offset above is non-zero, force
data address to be at start of text + offset */
void
elf_linkcmd(char *buf,
size_t len,
const char *kernel,
const char *entry,
const char *outfile,
const void *address,
const char *object)
{
ssize_t n;
if (data_offset == NULL)
n = snprintf(buf, len, LINKCMD, kernel, entry,
outfile, address, object);
else
n = snprintf(buf, len, LINKCMD2, kernel, entry,
outfile, address,
(const char*)address + data_offset, object);
if (n >= len)
errx(1, "link command longer than %lu bytes", (u_long)len);
}
/* load a prelinked module; returns entry point */
void *
elf_mod_load(int fd)
{
Elf_Ehdr ehdr;
size_t zero_size = 0;
size_t b;
ssize_t n;
char *strtab;
struct elf_section *head, *s;
char buf[10 * BUFSIZ];
void *addr = NULL;
if (read_elf_header(fd, &ehdr) < 0)
return NULL;
strtab = read_string_table(fd, &ehdr);
read_sections(fd, &ehdr, strtab, &head);
for (s = head; s; s = s->next) {
if (debug)
fprintf(stderr, "loading `%s': addr = %p, "
"size = %#lx\n",
s->name, s->addr, (u_long)s->size);
if (s->type == Elf_sht_nobits)
/* skip some space */
zero_size += s->size;
else {
if (addr != NULL) {
/* if there is a gap in the prelinked
module, transfer some empty
space... */
zero_size += (char*)s->addr - (char*)addr;
}
if (zero_size) {
loadspace(zero_size);
zero_size = 0;
}
b = s->size;
if (lseek(fd, s->offset, SEEK_SET) == -1)
err(1, "lseek");
while (b) {
n = read(fd, buf, MIN(b, sizeof(buf)));
if (n == 0)
errx(1, "unexpected EOF");
if (n < 0)
err(1, "read");
loadbuf(buf, n);
b -= n;
}
addr = (char*)s->addr + s->size;
}
}
/* any trailing zero_space will be filled with zeros by the
LKM framework */
free_sections(head);
free(strtab);
return (void*)ehdr.e_entry;
}
void
elf_mod_symload(strtablen)
int strtablen;
{
warnx("ELF can not load symbols");
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: modload.8,v 1.11 1999/04/30 18:32:01 ross Exp $
.\" $NetBSD: modload.8,v 1.12 1999/06/13 12:54:40 mrg Exp $
.\"
.\" Copyright (c) 1993 Christopher G. Demetriou
.\" All rights reserved.
@ -33,7 +33,7 @@
.Nd load a kernel module
.Sh SYNOPSIS
.Nm ""
.Op Fl dvs
.Op Fl dnvsS
.Op Fl A Ar kernel
.Op Fl e Ar entry
.Op Fl p Ar postinstall
@ -53,10 +53,17 @@ are as follows:
Debug. Used to debug
.Nm
itself.
.It Fl n
Do everything, except calling the module entry point (and any
post-install program).
.It Fl v
Print comments about the loading process.
.It Fl s
Load the symbol table.
.It Fl S
Do not remove the temporary object file. By default, the
.Xr ld 1
output is removed after being loaded into the kernel.
.It Fl A Ar kernel
Specify the file that is passed to the linker
to resolve module references to external symbols.

View File

@ -1,4 +1,4 @@
/* $NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $ */
/* $NetBSD: modload.c,v 1.25 1999/06/13 12:54:40 mrg Exp $ */
/*
* Copyright (c) 1993 Terrence R. Lambert.
@ -34,7 +34,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $");
__RCSID("$NetBSD: modload.c,v 1.25 1999/06/13 12:54:40 mrg Exp $");
#endif /* not lint */
#include <sys/param.h>
@ -44,7 +44,6 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $");
#include <sys/lkm.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <a.out.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
@ -57,6 +56,8 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $");
#define TRUE 1
#define FALSE 0
#include "modload.h"
#ifndef DFLT_ENTRY
#define DFLT_ENTRY "xxxinit"
#endif /* !DFLT_ENTRY */
@ -64,46 +65,30 @@ __RCSID("$NetBSD: modload.c,v 1.24 1999/04/30 18:32:01 ross Exp $");
#define DFLT_ENTRYEXT "_lkmentry"
#endif /* !DFLT_ENTRYEXT */
/*
* Expected linker options:
*
* -A executable to link against
* -e entry point
* -o output file
* -T address to link to in hex (assumes it's a page boundry)
* <target> object file
*/
#ifdef __alpha__
#define LINKCMD "ld -R %s -e %s -o %s -Ttext %x %s"
#else
#define LINKCMD "ld -A %s -e _%s -o %s -T %x %s"
#endif
void cleanup __P((void));
int linkcmd __P((char *, char *, char *, u_int, char *));
int main __P((int, char *[]));
void usage __P((void));
int verify_entry __P((char *, char *));
int debug = 0;
int verbose = 0;
char *out = NULL;
int symtab = 0;
int Sflag;
int
linkcmd(kernel, entry, outfile, address, object)
char *kernel, *entry, *outfile;
u_int address; /* XXX */
char *object;
static void cleanup __P((void));
/* prelink the module */
static int
prelink(const char *kernel,
const char *entry,
const char *outfile,
const void *address,
const char *object)
{
char cmdbuf[1024];
int error = 0;
if (snprintf(cmdbuf, sizeof(cmdbuf), LINKCMD, kernel, entry, outfile,
address, object) >= sizeof(cmdbuf))
errx(1, "link command too long");
linkcmd(cmdbuf, sizeof(cmdbuf),
kernel, entry, outfile, address, object);
if (debug)
printf("%s\n", cmdbuf);
fprintf(stderr, "%s\n", cmdbuf);
switch (system(cmdbuf)) {
case 0: /* SUCCESS! */
@ -128,14 +113,14 @@ linkcmd(kernel, entry, outfile, address, object)
return error;
}
void
usage()
static void
usage(void)
{
fprintf(stderr, "usage:\n");
fprintf(stderr, "modload [-d] [-v] [-A <kernel>] [-e <entry]\n");
fprintf(stderr, "modload [-d] [-v] [-n] [-A <kernel>] [-e <entry>]\n");
fprintf(stderr,
"[-p <postinstall>] [-o <output file>] <input file>\n");
" [-p <postinstall>] [-o <output file>] <input file>\n");
exit(1);
}
@ -143,12 +128,15 @@ int fileopen = 0;
#define DEV_OPEN 0x01
#define MOD_OPEN 0x02
#define PART_RESRV 0x04
#define OUTFILE_CREAT 0x08
int devfd, modfd;
struct lmc_resrv resrv;
void
cleanup()
static void
cleanup(void)
{
if (fileopen & PART_RESRV) {
/*
* Free up kernel memory
@ -162,11 +150,13 @@ cleanup()
if (fileopen & MOD_OPEN)
close(modfd);
if (fileopen & OUTFILE_CREAT)
unlink(out);
}
int
verify_entry(entry, filename)
char *entry, *filename;
static int
verify_entry(char *entry, char *filename)
{
struct nlist names[2];
int n;
@ -188,31 +178,58 @@ verify_entry(entry, filename)
return n;
}
/*
* Transfer data to kernel memory in chunks
* of MODIOBUF size at a time.
*/
void
loadbuf(void *buf, size_t len)
{
struct lmc_loadbuf ldbuf;
size_t n;
char *p = buf;
while(len) {
n = MIN(len, MODIOBUF);
ldbuf.cnt = n;
ldbuf.data = p;
if(ioctl(devfd, LMLOADBUF, &ldbuf) == -1)
err(11, "error loading buffer");
len -= n;
p += n;
}
}
/* Transfer some empty space. */
void
loadspace(size_t len)
{
char buf[MODIOBUF];
size_t n;
memset(buf, 0, sizeof(buf));
while(len) {
n = MIN(len, sizeof(buf));
loadbuf(buf, n);
len -= n;
}
}
int
main(argc, argv)
int argc;
char *argv[];
main(int argc, char **argv)
{
int c;
char *kname = _PATH_UNIX;
char *entry = DFLT_ENTRY;
char *post = NULL;
char *out = NULL;
char *modobj;
char modout[80], *p;
struct exec info_buf;
struct stat stb;
u_int modsize; /* XXX */
u_int modentry; /* XXX */
struct nlist *nlp;
int strtablen, numsyms;
int strtablen;
size_t modsize; /* XXX */
void* modentry; /* XXX */
int noready = 0, old = 0;
struct lmc_loadbuf ldbuf;
int sz, bytesleft, old = FALSE;
char buf[MODIOBUF];
char *symbuf;
while ((c = getopt(argc, argv, "dvsA:e:p:o:")) != -1) {
while ((c = getopt(argc, argv, "dnvsAS:e:p:o:")) != -1) {
switch (c) {
case 'd':
debug = 1;
@ -232,11 +249,18 @@ main(argc, argv)
case 'o':
out = optarg;
break; /* output file */
case 'n':
noready = 1;
break;
case 's':
symtab = 1;
break;
case 'S':
Sflag = 1;
break;
case '?':
usage();
/* NOTREACHED */
default:
printf("default!\n");
break;
@ -261,7 +285,8 @@ main(argc, argv)
err(3, _PATH_LKM);
fileopen |= DEV_OPEN;
strcpy(modout, modobj);
strncpy(modout, modobj, sizeof(modout) - 1);
modout[sizeof(modout) - 1] = '\0';
p = strrchr(modout, '.');
if (!p || strcmp(p, ".o"))
@ -282,7 +307,7 @@ main(argc, argv)
p++;
else
p = modout;
entry = (char *)malloc(strlen(p) +
entry = malloc(strlen(p) +
strlen(DFLT_ENTRYEXT) + 1);
strcpy(entry, p);
strcat(entry, DFLT_ENTRYEXT);
@ -297,45 +322,36 @@ main(argc, argv)
/*
* Prelink to get file size
*/
if (linkcmd(kname, entry, out, 0, modobj))
if (prelink(kname, entry, out, 0, modobj))
errx(1, "can't prelink `%s' creating `%s'", modobj, out);
/*
* Pre-open the 0-linked module to get the size information
*/
if (Sflag == 0)
fileopen |= OUTFILE_CREAT;
/*
* Pre-open the 0-linked module to get the size information
*/
if ((modfd = open(out, O_RDONLY, 0)) == -1)
err(4, out);
err(4, "%s", out);
fileopen |= MOD_OPEN;
/*
* Get the load module post load size... do this by reading the
* header and doing page counts.
*/
if (read(modfd, &info_buf, sizeof(struct exec)) == -1)
err(3, "read `%s'", out);
/*
* stat for filesize to figure out string table size
*/
if (fstat(modfd, &stb) == -1)
err(3, "fstat `%s'", out);
/*
* work out various sizes and fill in resrv bits
*/
if (mod_sizes(modfd, &modsize, &strtablen, &resrv, &stb) != 0)
err(1, "can't get module sizes");
/*
* Close the dummy module -- we have our sizing information.
*/
close(modfd);
fileopen &= ~MOD_OPEN;
/*
* Magic number...
*/
if (N_BADMAG(info_buf))
errx(4, "not an a.out format file");
/*
* Calculate the size of the module
*/
modsize = info_buf.a_text + info_buf.a_data + info_buf.a_bss;
/*
* Reserve the required amount of kernel memory -- this may fail
* to be successful.
@ -344,16 +360,9 @@ main(argc, argv)
resrv.name = modout; /* objname w/o ".o" */
resrv.slot = -1; /* returned */
resrv.addr = 0; /* returned */
strtablen = stb.st_size - N_STROFF(info_buf);
if (symtab) {
/* XXX TODO: grovel through symbol table looking
for just the symbol table stuff from the new module,
and skip the stuff from the kernel. */
resrv.sym_size = info_buf.a_syms + strtablen;
resrv.sym_symsize = info_buf.a_syms;
} else
resrv.sym_size = resrv.sym_symsize = 0;
if (verbose)
warnx("reserving %lu bytes of memory", (unsigned long)modsize);
if (ioctl(devfd, LMRESERV, &resrv) == -1) {
if (symtab)
warn("not loading symbols: kernel does not support symbol table loading");
@ -368,118 +377,32 @@ main(argc, argv)
/*
* Relink at kernel load address
*/
if (linkcmd(kname, entry, out, resrv.addr, modobj))
errx(1, "can't link `%s' creating `%s' bound to 0x%08lx",
modobj, out, (long) resrv.addr);
if (prelink(kname, entry, out, (void*)resrv.addr, modobj))
errx(1, "can't link `%s' creating `%s' bound to %p",
modobj, out, (void*)resrv.addr);
/*
* Open the relinked module to load it...
*/
if ((modfd = open(out, O_RDONLY, 0)) == -1)
err(4, out);
err(4, "%s", out);
fileopen |= MOD_OPEN;
/*
* Reread the header to get the actual entry point *after* the
* relink.
*/
if (read(modfd, &info_buf, sizeof(struct exec)) == -1)
err(3, "read `%s'", out);
modentry = mod_load(modfd);
if (debug)
fprintf(stderr, "modentry = %p\n", modentry);
/*
* Get the entry point (for initialization)
*/
modentry = info_buf.a_entry; /* place to call */
if (symtab)
mod_symload(strtablen);
/*
* Seek to the text offset to start loading...
*/
if (lseek(modfd, N_TXTOFF(info_buf), 0) == -1)
err(12, "lseek");
/*
* Transfer the relinked module to kernel memory in chunks of
* MODIOBUF size at a time.
*/
for (bytesleft = info_buf.a_text + info_buf.a_data;
bytesleft > 0;
bytesleft -= sz) {
sz = MIN(bytesleft, MODIOBUF);
read(modfd, buf, sz);
ldbuf.cnt = sz;
ldbuf.data = buf;
if (ioctl(devfd, LMLOADBUF, &ldbuf) == -1)
err(11, "error transferring buffer");
}
if (symtab) {
/*
* Seek to the symbol table to start loading it...
*/
if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1)
err(12, "lseek");
/*
* Transfer the symbol table entries. First, read them all in,
* then adjust their string table pointers, then
* copy in bulk. Then copy the string table itself.
*/
symbuf = malloc(info_buf.a_syms);
if (symbuf == 0)
err(13, "malloc");
if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms)
err(14, "read");
numsyms = info_buf.a_syms / sizeof(struct nlist);
for (nlp = (struct nlist *)symbuf;
(char *)nlp < symbuf + info_buf.a_syms;
nlp++) {
register int strx;
strx = nlp->n_un.n_strx;
if (strx != 0) {
/* If a valid name, set the name ptr to point at the
* loaded address for the string in the string table.
*/
if (strx > strtablen)
nlp->n_un.n_name = 0;
else
nlp->n_un.n_name =
(char *)(strx + resrv.sym_addr + info_buf.a_syms);
}
}
/*
* we've fixed the symbol table entries, now load them
*/
for (bytesleft = info_buf.a_syms;
bytesleft > 0;
bytesleft -= sz) {
sz = MIN(bytesleft, MODIOBUF);
ldbuf.cnt = sz;
ldbuf.data = symbuf;
if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
err(11, "error transferring sym buffer");
symbuf += sz;
}
free(symbuf - info_buf.a_syms);
/* and now read the string table and load it. */
for (bytesleft = strtablen;
bytesleft > 0;
bytesleft -= sz) {
sz = MIN(bytesleft, MODIOBUF);
read(modfd, buf, sz);
ldbuf.cnt = sz;
ldbuf.data = buf;
if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1)
err(11, "error transferring stringtable buffer");
}
}
/*
* Save ourselves before disaster (potentitally) strikes...
*/
sync();
if (noready)
return 0;
/*
* Trigger the module as loaded by calling the entry procedure;
* this will do all necessary table fixup to ensure that state
@ -528,5 +451,5 @@ main(argc, argv)
err(16, "can't exec `%s'", post);
}
return 0;
exit (0);
}

70
sbin/modload/modload.h Normal file
View File

@ -0,0 +1,70 @@
/* $NetBSD: modload.h,v 1.1 1999/06/13 12:54:40 mrg Exp $ */
/*
* Copyright (c) 1993 Terrence R. Lambert.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Terrence R. Lambert.
* 4. The name Terrence R. Lambert may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __modload_h__
#define __modload_h__
int elf_mod_sizes __P((int, size_t *, int *, struct lmc_resrv *,
struct stat *));
void *elf_mod_load __P((int));
void elf_linkcmd __P((char*, size_t, const char*, const char*,
const char*, const void*, const char*));
void elf_mod_symload __P((int));
int a_out_mod_sizes __P((int, size_t *, int *, struct lmc_resrv *,
struct stat *));
void *a_out_mod_load __P((int));
void a_out_linkcmd __P((char*, size_t, const char*, const char*,
const char*, const void*, const char*));
void a_out_mod_symload __P((int));
#ifndef USE_AOUT
#define mod_sizes elf_mod_sizes
#define mod_load elf_mod_load
#define mod_symload elf_mod_symload
#define linkcmd elf_linkcmd
#else
#define mod_sizes a_out_mod_sizes
#define mod_load a_out_mod_load
#define mod_symload a_out_mod_symload
#define linkcmd a_out_linkcmd
#endif
void loadbuf(void*, size_t);
void loadspace(size_t);
extern int debug;
extern int verbose;
#endif /* __modload_h__ */