Added insmod support for ARM, and lsmod support for older kernels,

thanks to Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
Nicolas Ferre <nicolas.ferre@alcove.fr>.
 -Erik
This commit is contained in:
Eric Andersen 2000-12-06 18:18:26 +00:00
parent e884970c87
commit 21adca750a
6 changed files with 512 additions and 205 deletions

View File

@ -3,9 +3,12 @@
* Matt Kraai -- fix all usage of TRUE and FALSE so all apps now * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now
return EXIT_SUCCESS or EXIT_FAILURE to the system. return EXIT_SUCCESS or EXIT_FAILURE to the system.
Now TRUE and FALSE are set to the C standard where TRUE=1. Now TRUE and FALSE are set to the C standard where TRUE=1.
* Fixed uname problem causing the kernel version to be * me -- Fixed uname problem causing the kernel version to be
mis-detected (causing problems with poweroff, init, mis-detected (causing problems with poweroff, init,
and other things). and other things).
* Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
Nicolas Ferre <nicolas.ferre@alcove.fr> -- insmod support on ARM
and StrongArm, and suport for lsmod on older 2.0.x kernels.
* Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use * Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use
an included shell script called unrpm as a front end to it. There's an included shell script called unrpm as a front end to it. There's
also a shell script called undeb included for debian packages. also a shell script called undeb included for debian packages.

View File

@ -260,6 +260,12 @@
// Support installing modules from kernel versions after 2.1.18 // Support installing modules from kernel versions after 2.1.18
#define BB_FEATURE_INSMOD_NEW_KERNEL #define BB_FEATURE_INSMOD_NEW_KERNEL
// //
// You must enable one or both of these features
// Support modules status from pre 2.1 kernels
//#define BB_FEATURE_LSMOD_OLD_KERNEL
// Support modules status from kernel versions after 2.1.18
#define BB_FEATURE_LSMOD_NEW_KERNEL
//
// Support module version checking // Support module version checking
//#define BB_FEATURE_INSMOD_VERSION_CHECKING //#define BB_FEATURE_INSMOD_VERSION_CHECKING
// //

315
insmod.c
View File

@ -7,11 +7,12 @@
* and Ron Alder <alder@lineo.com> * and Ron Alder <alder@lineo.com>
* *
* Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4 * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
* and (theoretically) SH3. Note that there is still no true * and (theoretically) SH3. I have only tested SH4 in little endian mode.
* multiple architecture support. You just get SH3|SH4|i386, despite *
* the mention of ARM and m68k--which may or may not work (but * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
* almost certainly do not, due to at least MATCH_MACHINE). I have * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
* only tested SH4 in little endian mode. * very minor changes required to also work with StrongArm and presumably
* all ARM based systems.
* *
* Based almost entirely on the Linux modutils-2.3.11 implementation. * Based almost entirely on the Linux modutils-2.3.11 implementation.
* Copyright 1996, 1997 Linux International. * Copyright 1996, 1997 Linux International.
@ -77,7 +78,7 @@
#ifndef MODUTILS_MODULE_H #ifndef MODUTILS_MODULE_H
#define MODUTILS_MODULE_H 1 #define MODUTILS_MODULE_H 1
#ident "$Id: insmod.c,v 1.29 2000/12/01 02:55:13 kraai Exp $" #ident "$Id: insmod.c,v 1.30 2000/12/06 18:18:26 andersen Exp $"
/* This file contains the structures used by the 2.0 and 2.1 kernels. /* This file contains the structures used by the 2.0 and 2.1 kernels.
We do not use the kernel headers directly because we do not wish We do not use the kernel headers directly because we do not wish
@ -283,7 +284,7 @@ int delete_module(const char *);
#ifndef MODUTILS_OBJ_H #ifndef MODUTILS_OBJ_H
#define MODUTILS_OBJ_H 1 #define MODUTILS_OBJ_H 1
#ident "$Id: insmod.c,v 1.29 2000/12/01 02:55:13 kraai Exp $" #ident "$Id: insmod.c,v 1.30 2000/12/06 18:18:26 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */ /* The relocatable object is manipulated using elfin types. */
@ -317,12 +318,17 @@ int delete_module(const char *);
#define SHT_RELM SHT_RELA #define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela #define Elf32_RelM Elf32_Rela
#else #elif defined(__arm__)
/* presumably we can use these for anything but the SH */ #define MATCH_MACHINE(x) (x == EM_ARM)
#define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel
#elif defined(__i386__)
/* presumably we can use these for anything but the SH and ARM*/
/* this is the previous behavior, but it does result in /* this is the previous behavior, but it does result in
insmod.c being broken on anything except i386 */ insmod.c being broken on anything except i386 */
#ifndef EM_486 #ifndef EM_486
#define MATCH_MACHINE(x) (x == EM_386) #define MATCH_MACHINE(x) (x == EM_386)
#else #else
@ -332,6 +338,8 @@ int delete_module(const char *);
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#else
#error insmod.c no platform specified
#endif #endif
#ifndef ElfW #ifndef ElfW
@ -531,6 +539,17 @@ int flag_export = 1;
and we can't support anything else right now anyway. In the and we can't support anything else right now anyway. In the
future maybe they should be #if defined'd */ future maybe they should be #if defined'd */
/* Done ;-) */
#if defined(__arm__)
struct arm_plt_entry
{
int offset;
int allocated:1;
int inited:1; /* has been set up */
};
#endif
struct arch_got_entry { struct arch_got_entry {
int offset; int offset;
unsigned offset_done:1; unsigned offset_done:1;
@ -539,11 +558,17 @@ struct arch_got_entry {
struct arch_file { struct arch_file {
struct obj_file root; struct obj_file root;
#if defined(__arm__)
struct obj_section *plt;
#endif
struct obj_section *got; struct obj_section *got;
}; };
struct arch_symbol { struct arch_symbol {
struct obj_symbol root; struct obj_symbol root;
#if defined(__arm__)
struct arm_plt_entry pltent;
#endif
struct arch_got_entry gotent; struct arch_got_entry gotent;
}; };
@ -590,6 +615,10 @@ extern int delete_module(const char *);
-- Bryan Rittmeyer <bryan@ixiacom.com> */ -- Bryan Rittmeyer <bryan@ixiacom.com> */
#ifdef BB_FEATURE_INSMOD_OLD_KERNEL
_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks)
#endif
#if defined(__i386__) || defined(__m68k__) || defined(__arm__) #if defined(__i386__) || defined(__m68k__) || defined(__arm__)
/* Jump through hoops to fixup error return codes */ /* Jump through hoops to fixup error return codes */
#define __NR__create_module __NR_create_module #define __NR__create_module __NR_create_module
@ -623,7 +652,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf,
if (fullName[0] == '\0') if (fullName[0] == '\0')
return (FALSE); return (FALSE);
else { else {
char *tmp = strrchr(fileName, '/'); char *tmp = strrchr((char *) fileName, '/');
if (tmp == NULL) if (tmp == NULL)
tmp = (char *) fileName; tmp = (char *) fileName;
@ -667,18 +696,20 @@ arch_apply_relocation(struct obj_file *f,
struct obj_section *targsec, struct obj_section *targsec,
struct obj_section *symsec, struct obj_section *symsec,
struct obj_symbol *sym, struct obj_symbol *sym,
#if defined(__sh__) ElfW(RelM) *rel, ElfW(Addr) v)
Elf32_Rela * rel, Elf32_Addr v)
#else
Elf32_Rel * rel, Elf32_Addr v)
#endif
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
struct arch_symbol *isym = (struct arch_symbol *) sym; struct arch_symbol *isym = (struct arch_symbol *) sym;
Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset); ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset; ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0; ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
#if defined(__arm__)
ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
struct arm_plt_entry *pe;
unsigned long *ip;
#endif
enum obj_reloc ret = obj_reloc_ok; enum obj_reloc ret = obj_reloc_ok;
@ -689,52 +720,91 @@ arch_apply_relocation(struct obj_file *f,
and in case that ever changes */ and in case that ever changes */
#if defined(__sh__) #if defined(__sh__)
case R_SH_NONE: case R_SH_NONE:
#else #elif defined(__arm__)
case R_ARM_NONE:
#elif defined(__i386__)
case R_386_NONE: case R_386_NONE:
#endif #endif
break; break;
#if defined(__sh__) #if defined(__sh__)
case R_SH_DIR32: case R_SH_DIR32:
#else #elif defined(__arm__)
case R_ARM_ABS32:
#elif defined(__i386__)
case R_386_32: case R_386_32:
#endif #endif
*loc += v; *loc += v;
break; break;
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_REL32: case R_SH_REL32:
#else
case R_386_PLT32:
case R_386_PC32:
#endif
*loc += v - dot; *loc += v - dot;
break; break;
#elif defined(__i386__)
case R_386_PLT32:
case R_386_PC32:
*loc += v - dot;
break;
#endif
#if defined(__sh__) #if defined(__sh__)
case R_SH_PLT32: case R_SH_PLT32:
*loc = v - dot; *loc = v - dot;
break; break;
#elif defined(__arm__)
case R_ARM_PC24:
case R_ARM_PLT32:
/* find the plt entry and initialize it if necessary */
assert(isym != NULL);
pe = (struct arm_plt_entry*) &isym->pltent;
if (! pe->inited) {
ip = (unsigned long *) (ifile->plt->contents + pe->offset);
ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
ip[1] = v; /* sym@ */
pe->inited = 1;
}
/* relative distance to target */
v -= dot;
/* if the target is too far away.... */
if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
/* go via the plt */
v = plt + pe->offset - dot;
}
if (v & 3)
ret = obj_reloc_dangerous;
/* Convert to words. */
v >>= 2;
/* merge the offset into the instruction. */
*loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
break;
#elif defined(__i386__)
#endif #endif
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_GLOB_DAT: case R_SH_GLOB_DAT:
case R_SH_JMP_SLOT: case R_SH_JMP_SLOT:
*loc = v; *loc = v;
break; break;
#else #elif defined(__i386__)
case R_386_GLOB_DAT: case R_386_GLOB_DAT:
case R_386_JMP_SLOT: case R_386_JMP_SLOT:
*loc = v; *loc = v;
break; break;
#endif #endif
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_RELATIVE: case R_SH_RELATIVE:
*loc += f->baseaddr + rel->r_addend; *loc += f->baseaddr + rel->r_addend;
break; break;
#else #elif defined(__i386__)
case R_386_RELATIVE: case R_386_RELATIVE:
*loc += f->baseaddr; *loc += f->baseaddr;
break; break;
@ -742,41 +812,46 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTPC: case R_SH_GOTPC:
assert(got != 0); #elif defined(__arm__)
*loc += got - dot + rel->r_addend;; case R_ARM_GOTPC:
break; #elif defined(__i386__)
#else
case R_386_GOTPC: case R_386_GOTPC:
assert(got != 0);
*loc += got - dot;
break;
#endif #endif
assert(got != 0);
#if defined(__sh__)
*loc += got - dot + rel->r_addend;;
#elif defined(__i386__) || defined(__arm__)
*loc += got - dot;
#endif
break;
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
assert(isym != NULL); #elif defined(__arm__)
if (!isym->gotent.reloc_done) { case R_ARM_GOT32:
isym->gotent.reloc_done = 1; #elif defined(__i386__)
*(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
v;
}
*loc += isym->gotent.offset + rel->r_addend;
break;
#else
case R_386_GOT32: case R_386_GOT32:
#endif
assert(isym != NULL); assert(isym != NULL);
/* needs an entry in the .got: set it, once */
if (!isym->gotent.reloc_done) { if (!isym->gotent.reloc_done) {
isym->gotent.reloc_done = 1; isym->gotent.reloc_done = 1;
*(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) = *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
v;
} }
/* make the reloc with_respect_to_.got */
#if defined(__sh__)
*loc += isym->gotent.offset + rel->r_addend;
#elif defined(__i386__) || defined(__arm__)
*loc += isym->gotent.offset; *loc += isym->gotent.offset;
break;
#endif #endif
break;
/* address relative to the got */
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTOFF: case R_SH_GOTOFF:
#else #elif defined(__arm__)
case R_ARM_GOTOFF:
#elif defined(__i386__)
case R_386_GOTOFF: case R_386_GOTOFF:
#endif #endif
assert(got != 0); assert(got != 0);
@ -784,6 +859,7 @@ arch_apply_relocation(struct obj_file *f,
break; break;
default: default:
printf("Warning: unhandled reloc %d\n",ELF32_R_TYPE(rel->r_info));
ret = obj_reloc_unhandled; ret = obj_reloc_unhandled;
break; break;
} }
@ -794,81 +870,111 @@ arch_apply_relocation(struct obj_file *f,
int arch_create_got(struct obj_file *f) int arch_create_got(struct obj_file *f)
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
int i, n, offset = 0, gotneeded = 0; int i, got_offset = 0, gotneeded = 0;
#if defined(__arm__)
n = ifile->root.header.e_shnum; int plt_offset = 0, pltneeded = 0;
for (i = 0; i < n; ++i) {
struct obj_section *relsec, *symsec, *strsec;
#if defined(__sh__)
Elf32_Rela *rel, *relend;
#else
Elf32_Rel *rel, *relend;
#endif #endif
Elf32_Sym *symtab; struct obj_section *relsec, *symsec, *strsec;
const char *strtab; ElfW(RelM) *rel, *relend;
ElfW(Sym) *symtab, *extsym;
const char *strtab, *name;
struct arch_symbol *intsym;
relsec = ifile->root.sections[i]; for (i = 0; i < f->header.e_shnum; ++i) {
if (relsec->header.sh_type != SHT_REL) relsec = f->sections[i];
if (relsec->header.sh_type != SHT_RELM)
continue; continue;
symsec = ifile->root.sections[relsec->header.sh_link]; symsec = f->sections[relsec->header.sh_link];
strsec = ifile->root.sections[symsec->header.sh_link]; strsec = f->sections[symsec->header.sh_link];
rel = (ElfW(RelM) *) relsec->contents;
#if defined(__sh__) relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
rel = (Elf32_Rela *) relsec->contents; symtab = (ElfW(Sym) *) symsec->contents;
relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
#else
rel = (Elf32_Rel *) relsec->contents;
relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
#endif
symtab = (Elf32_Sym *) symsec->contents;
strtab = (const char *) strsec->contents; strtab = (const char *) strsec->contents;
for (; rel < relend; ++rel) { for (; rel < relend; ++rel) {
Elf32_Sym *extsym; extsym = &symtab[ELF32_R_SYM(rel->r_info)];
struct arch_symbol *intsym;
const char *name;
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
#if defined(__sh__) #if defined(__arm__)
case R_SH_GOTPC: case R_ARM_GOT32:
case R_SH_GOTOFF: #elif defined(__sh__)
#else
case R_386_GOTPC:
case R_386_GOTOFF:
#endif
gotneeded = 1;
default:
continue;
#if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
#else #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif #endif
break; break;
#if defined(__arm__)
case R_ARM_PC24:
case R_ARM_PLT32:
pltneeded = 1;
break;
case R_ARM_GOTPC:
case R_ARM_GOTOFF:
gotneeded = 1;
if (got_offset == 0)
got_offset = 4;
#elif defined(__sh__)
case R_SH_GOTPC:
case R_SH_GOTOFF:
gotneeded = 1;
#elif defined(__i386__)
case R_386_GOTPC:
case R_386_GOTOFF:
gotneeded = 1;
#endif
default:
continue;
} }
extsym = &symtab[ELF32_R_SYM(rel->r_info)]; if (extsym->st_name != 0) {
if (extsym->st_name)
name = strtab + extsym->st_name; name = strtab + extsym->st_name;
else } else {
name = f->sections[extsym->st_shndx]->name; name = f->sections[extsym->st_shndx]->name;
intsym = }
(struct arch_symbol *) obj_find_symbol(&ifile->root, name); intsym = (struct arch_symbol *) obj_find_symbol(f, name);
if (!intsym->gotent.offset_done) { if (!intsym->gotent.offset_done) {
intsym->gotent.offset_done = 1; intsym->gotent.offset_done = 1;
intsym->gotent.offset = offset; intsym->gotent.offset = got_offset;
offset += 4; got_offset += 4;
} }
#if defined(__arm__)
if (pltneeded && intsym->pltent.allocated == 0) {
intsym->pltent.allocated = 1;
intsym->pltent.offset = plt_offset;
plt_offset += 8;
intsym->pltent.inited = 0;
pltneeded = 0;
}
#endif
} }
} }
if (offset > 0 || gotneeded) #if defined(__arm__)
ifile->got = if (got_offset) {
obj_create_alloced_section(&ifile->root, ".got", 4, offset); struct obj_section* relsec = obj_find_section(f, ".got");
if (relsec) {
obj_extend_section(relsec, got_offset);
} else {
relsec = obj_create_alloced_section(f, ".got", 8, got_offset);
assert(relsec);
}
ifile->got = relsec;
}
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
#else
if (got_offset > 0 || gotneeded)
ifile->got = obj_create_alloced_section(f, ".got", 4, got_offset);
#endif
return 1; return 1;
} }
@ -1598,7 +1704,7 @@ old_init_module(const char *m_name, struct obj_file *f,
ksym->name = ksym->name =
(unsigned long) str - (unsigned long) symtab; (unsigned long) str - (unsigned long) symtab;
str = stpcpy(str, sym->name) + 1; str = strcpy(str, sym->name) + 1;
ksym++; ksym++;
} }
} }
@ -2201,8 +2307,9 @@ new_init_module(const char *m_name, struct obj_file *f,
#define new_init_module(x, y, z) TRUE #define new_init_module(x, y, z) TRUE
#define new_create_this_module(x, y) 0 #define new_create_this_module(x, y) 0
#define new_create_module_ksymtab(x) #define new_create_module_ksymtab(x)
#define query_module(v, w, x, y, z) -1
#endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ #endif /* BB_FEATURE_INSMOD_NEW_KERNEL */
/*======================================================================*/ /*======================================================================*/
@ -2372,8 +2479,12 @@ void obj_allocate_commons(struct obj_file *f)
for (i = 0; i < f->header.e_shnum; ++i) { for (i = 0; i < f->header.e_shnum; ++i) {
struct obj_section *s = f->sections[i]; struct obj_section *s = f->sections[i];
if (s->header.sh_type == SHT_NOBITS) { if (s->header.sh_type == SHT_NOBITS) {
if (s->header.sh_size != 0)
s->contents = memset(xmalloc(s->header.sh_size), s->contents = memset(xmalloc(s->header.sh_size),
0, s->header.sh_size); 0, s->header.sh_size);
else
s->contents = NULL;
s->header.sh_type = SHT_PROGBITS; s->header.sh_type = SHT_PROGBITS;
} }
} }

38
lsmod.c
View File

@ -5,6 +5,10 @@
* Copyright (C) 1999,2000 by Lineo, inc. * Copyright (C) 1999,2000 by Lineo, inc.
* Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
* *
* Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
* Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
* (which lack the query_module() interface).
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -32,9 +36,16 @@
#include <assert.h> #include <assert.h>
#include <getopt.h> #include <getopt.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/file.h>
#if !defined(BB_FEATURE_LSMOD_NEW_KERNEL) && !defined(BB_FEATURE_LSMOD_OLD_KERNEL)
#error "Must have ether BB_FEATURE_LSMOD_NEW_KERNEL or BB_FEATURE_LSMOD_OLD_KERNEL defined"
#endif
#ifdef BB_FEATURE_LSMOD_NEW_KERNEL
struct module_info struct module_info
{ {
unsigned long addr; unsigned long addr;
@ -120,3 +131,30 @@ extern int lsmod_main(int argc, char **argv)
return( 0); return( 0);
} }
#else /*BB_FEATURE_LSMOD_OLD_KERNEL*/
#if ! defined BB_FEATURE_USE_PROCFS
#error Sorry, I depend on the /proc filesystem right now.
#endif
extern int lsmod_main(int argc, char **argv)
{
int fd, i;
char line[128];
puts("Module Size Used by");
fflush(stdout);
if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
while ((i = read(fd, line, sizeof(line))) > 0) {
write(fileno(stdout), line, i);
}
close(fd);
return 0;
}
fatalError("/proc/modules: %s\n", strerror(errno));
return 1;
}
#endif /*BB_FEATURE_LSMOD_OLD_KERNEL*/

View File

@ -7,11 +7,12 @@
* and Ron Alder <alder@lineo.com> * and Ron Alder <alder@lineo.com>
* *
* Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4 * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
* and (theoretically) SH3. Note that there is still no true * and (theoretically) SH3. I have only tested SH4 in little endian mode.
* multiple architecture support. You just get SH3|SH4|i386, despite *
* the mention of ARM and m68k--which may or may not work (but * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
* almost certainly do not, due to at least MATCH_MACHINE). I have * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
* only tested SH4 in little endian mode. * very minor changes required to also work with StrongArm and presumably
* all ARM based systems.
* *
* Based almost entirely on the Linux modutils-2.3.11 implementation. * Based almost entirely on the Linux modutils-2.3.11 implementation.
* Copyright 1996, 1997 Linux International. * Copyright 1996, 1997 Linux International.
@ -77,7 +78,7 @@
#ifndef MODUTILS_MODULE_H #ifndef MODUTILS_MODULE_H
#define MODUTILS_MODULE_H 1 #define MODUTILS_MODULE_H 1
#ident "$Id: insmod.c,v 1.29 2000/12/01 02:55:13 kraai Exp $" #ident "$Id: insmod.c,v 1.30 2000/12/06 18:18:26 andersen Exp $"
/* This file contains the structures used by the 2.0 and 2.1 kernels. /* This file contains the structures used by the 2.0 and 2.1 kernels.
We do not use the kernel headers directly because we do not wish We do not use the kernel headers directly because we do not wish
@ -283,7 +284,7 @@ int delete_module(const char *);
#ifndef MODUTILS_OBJ_H #ifndef MODUTILS_OBJ_H
#define MODUTILS_OBJ_H 1 #define MODUTILS_OBJ_H 1
#ident "$Id: insmod.c,v 1.29 2000/12/01 02:55:13 kraai Exp $" #ident "$Id: insmod.c,v 1.30 2000/12/06 18:18:26 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */ /* The relocatable object is manipulated using elfin types. */
@ -317,12 +318,17 @@ int delete_module(const char *);
#define SHT_RELM SHT_RELA #define SHT_RELM SHT_RELA
#define Elf32_RelM Elf32_Rela #define Elf32_RelM Elf32_Rela
#else #elif defined(__arm__)
/* presumably we can use these for anything but the SH */ #define MATCH_MACHINE(x) (x == EM_ARM)
#define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel
#elif defined(__i386__)
/* presumably we can use these for anything but the SH and ARM*/
/* this is the previous behavior, but it does result in /* this is the previous behavior, but it does result in
insmod.c being broken on anything except i386 */ insmod.c being broken on anything except i386 */
#ifndef EM_486 #ifndef EM_486
#define MATCH_MACHINE(x) (x == EM_386) #define MATCH_MACHINE(x) (x == EM_386)
#else #else
@ -332,6 +338,8 @@ int delete_module(const char *);
#define SHT_RELM SHT_REL #define SHT_RELM SHT_REL
#define Elf32_RelM Elf32_Rel #define Elf32_RelM Elf32_Rel
#else
#error insmod.c no platform specified
#endif #endif
#ifndef ElfW #ifndef ElfW
@ -531,6 +539,17 @@ int flag_export = 1;
and we can't support anything else right now anyway. In the and we can't support anything else right now anyway. In the
future maybe they should be #if defined'd */ future maybe they should be #if defined'd */
/* Done ;-) */
#if defined(__arm__)
struct arm_plt_entry
{
int offset;
int allocated:1;
int inited:1; /* has been set up */
};
#endif
struct arch_got_entry { struct arch_got_entry {
int offset; int offset;
unsigned offset_done:1; unsigned offset_done:1;
@ -539,11 +558,17 @@ struct arch_got_entry {
struct arch_file { struct arch_file {
struct obj_file root; struct obj_file root;
#if defined(__arm__)
struct obj_section *plt;
#endif
struct obj_section *got; struct obj_section *got;
}; };
struct arch_symbol { struct arch_symbol {
struct obj_symbol root; struct obj_symbol root;
#if defined(__arm__)
struct arm_plt_entry pltent;
#endif
struct arch_got_entry gotent; struct arch_got_entry gotent;
}; };
@ -590,6 +615,10 @@ extern int delete_module(const char *);
-- Bryan Rittmeyer <bryan@ixiacom.com> */ -- Bryan Rittmeyer <bryan@ixiacom.com> */
#ifdef BB_FEATURE_INSMOD_OLD_KERNEL
_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ks)
#endif
#if defined(__i386__) || defined(__m68k__) || defined(__arm__) #if defined(__i386__) || defined(__m68k__) || defined(__arm__)
/* Jump through hoops to fixup error return codes */ /* Jump through hoops to fixup error return codes */
#define __NR__create_module __NR_create_module #define __NR__create_module __NR_create_module
@ -623,7 +652,7 @@ static int findNamedModule(const char *fileName, struct stat *statbuf,
if (fullName[0] == '\0') if (fullName[0] == '\0')
return (FALSE); return (FALSE);
else { else {
char *tmp = strrchr(fileName, '/'); char *tmp = strrchr((char *) fileName, '/');
if (tmp == NULL) if (tmp == NULL)
tmp = (char *) fileName; tmp = (char *) fileName;
@ -667,18 +696,20 @@ arch_apply_relocation(struct obj_file *f,
struct obj_section *targsec, struct obj_section *targsec,
struct obj_section *symsec, struct obj_section *symsec,
struct obj_symbol *sym, struct obj_symbol *sym,
#if defined(__sh__) ElfW(RelM) *rel, ElfW(Addr) v)
Elf32_Rela * rel, Elf32_Addr v)
#else
Elf32_Rel * rel, Elf32_Addr v)
#endif
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
struct arch_symbol *isym = (struct arch_symbol *) sym; struct arch_symbol *isym = (struct arch_symbol *) sym;
Elf32_Addr *loc = (Elf32_Addr *) (targsec->contents + rel->r_offset); ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset; ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0; ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
#if defined(__arm__)
ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
struct arm_plt_entry *pe;
unsigned long *ip;
#endif
enum obj_reloc ret = obj_reloc_ok; enum obj_reloc ret = obj_reloc_ok;
@ -689,52 +720,91 @@ arch_apply_relocation(struct obj_file *f,
and in case that ever changes */ and in case that ever changes */
#if defined(__sh__) #if defined(__sh__)
case R_SH_NONE: case R_SH_NONE:
#else #elif defined(__arm__)
case R_ARM_NONE:
#elif defined(__i386__)
case R_386_NONE: case R_386_NONE:
#endif #endif
break; break;
#if defined(__sh__) #if defined(__sh__)
case R_SH_DIR32: case R_SH_DIR32:
#else #elif defined(__arm__)
case R_ARM_ABS32:
#elif defined(__i386__)
case R_386_32: case R_386_32:
#endif #endif
*loc += v; *loc += v;
break; break;
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_REL32: case R_SH_REL32:
#else
case R_386_PLT32:
case R_386_PC32:
#endif
*loc += v - dot; *loc += v - dot;
break; break;
#elif defined(__i386__)
case R_386_PLT32:
case R_386_PC32:
*loc += v - dot;
break;
#endif
#if defined(__sh__) #if defined(__sh__)
case R_SH_PLT32: case R_SH_PLT32:
*loc = v - dot; *loc = v - dot;
break; break;
#elif defined(__arm__)
case R_ARM_PC24:
case R_ARM_PLT32:
/* find the plt entry and initialize it if necessary */
assert(isym != NULL);
pe = (struct arm_plt_entry*) &isym->pltent;
if (! pe->inited) {
ip = (unsigned long *) (ifile->plt->contents + pe->offset);
ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
ip[1] = v; /* sym@ */
pe->inited = 1;
}
/* relative distance to target */
v -= dot;
/* if the target is too far away.... */
if ((int)v < -0x02000000 || (int)v >= 0x02000000) {
/* go via the plt */
v = plt + pe->offset - dot;
}
if (v & 3)
ret = obj_reloc_dangerous;
/* Convert to words. */
v >>= 2;
/* merge the offset into the instruction. */
*loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
break;
#elif defined(__i386__)
#endif #endif
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_GLOB_DAT: case R_SH_GLOB_DAT:
case R_SH_JMP_SLOT: case R_SH_JMP_SLOT:
*loc = v; *loc = v;
break; break;
#else #elif defined(__i386__)
case R_386_GLOB_DAT: case R_386_GLOB_DAT:
case R_386_JMP_SLOT: case R_386_JMP_SLOT:
*loc = v; *loc = v;
break; break;
#endif #endif
#if defined(__sh__) #if defined(__arm__)
#elif defined(__sh__)
case R_SH_RELATIVE: case R_SH_RELATIVE:
*loc += f->baseaddr + rel->r_addend; *loc += f->baseaddr + rel->r_addend;
break; break;
#else #elif defined(__i386__)
case R_386_RELATIVE: case R_386_RELATIVE:
*loc += f->baseaddr; *loc += f->baseaddr;
break; break;
@ -742,41 +812,46 @@ arch_apply_relocation(struct obj_file *f,
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTPC: case R_SH_GOTPC:
assert(got != 0); #elif defined(__arm__)
*loc += got - dot + rel->r_addend;; case R_ARM_GOTPC:
break; #elif defined(__i386__)
#else
case R_386_GOTPC: case R_386_GOTPC:
assert(got != 0);
*loc += got - dot;
break;
#endif #endif
assert(got != 0);
#if defined(__sh__)
*loc += got - dot + rel->r_addend;;
#elif defined(__i386__) || defined(__arm__)
*loc += got - dot;
#endif
break;
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
assert(isym != NULL); #elif defined(__arm__)
if (!isym->gotent.reloc_done) { case R_ARM_GOT32:
isym->gotent.reloc_done = 1; #elif defined(__i386__)
*(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) =
v;
}
*loc += isym->gotent.offset + rel->r_addend;
break;
#else
case R_386_GOT32: case R_386_GOT32:
#endif
assert(isym != NULL); assert(isym != NULL);
/* needs an entry in the .got: set it, once */
if (!isym->gotent.reloc_done) { if (!isym->gotent.reloc_done) {
isym->gotent.reloc_done = 1; isym->gotent.reloc_done = 1;
*(Elf32_Addr *) (ifile->got->contents + isym->gotent.offset) = *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
v;
} }
/* make the reloc with_respect_to_.got */
#if defined(__sh__)
*loc += isym->gotent.offset + rel->r_addend;
#elif defined(__i386__) || defined(__arm__)
*loc += isym->gotent.offset; *loc += isym->gotent.offset;
break;
#endif #endif
break;
/* address relative to the got */
#if defined(__sh__) #if defined(__sh__)
case R_SH_GOTOFF: case R_SH_GOTOFF:
#else #elif defined(__arm__)
case R_ARM_GOTOFF:
#elif defined(__i386__)
case R_386_GOTOFF: case R_386_GOTOFF:
#endif #endif
assert(got != 0); assert(got != 0);
@ -784,6 +859,7 @@ arch_apply_relocation(struct obj_file *f,
break; break;
default: default:
printf("Warning: unhandled reloc %d\n",ELF32_R_TYPE(rel->r_info));
ret = obj_reloc_unhandled; ret = obj_reloc_unhandled;
break; break;
} }
@ -794,81 +870,111 @@ arch_apply_relocation(struct obj_file *f,
int arch_create_got(struct obj_file *f) int arch_create_got(struct obj_file *f)
{ {
struct arch_file *ifile = (struct arch_file *) f; struct arch_file *ifile = (struct arch_file *) f;
int i, n, offset = 0, gotneeded = 0; int i, got_offset = 0, gotneeded = 0;
#if defined(__arm__)
n = ifile->root.header.e_shnum; int plt_offset = 0, pltneeded = 0;
for (i = 0; i < n; ++i) {
struct obj_section *relsec, *symsec, *strsec;
#if defined(__sh__)
Elf32_Rela *rel, *relend;
#else
Elf32_Rel *rel, *relend;
#endif #endif
Elf32_Sym *symtab; struct obj_section *relsec, *symsec, *strsec;
const char *strtab; ElfW(RelM) *rel, *relend;
ElfW(Sym) *symtab, *extsym;
const char *strtab, *name;
struct arch_symbol *intsym;
relsec = ifile->root.sections[i]; for (i = 0; i < f->header.e_shnum; ++i) {
if (relsec->header.sh_type != SHT_REL) relsec = f->sections[i];
if (relsec->header.sh_type != SHT_RELM)
continue; continue;
symsec = ifile->root.sections[relsec->header.sh_link]; symsec = f->sections[relsec->header.sh_link];
strsec = ifile->root.sections[symsec->header.sh_link]; strsec = f->sections[symsec->header.sh_link];
rel = (ElfW(RelM) *) relsec->contents;
#if defined(__sh__) relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
rel = (Elf32_Rela *) relsec->contents; symtab = (ElfW(Sym) *) symsec->contents;
relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
#else
rel = (Elf32_Rel *) relsec->contents;
relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
#endif
symtab = (Elf32_Sym *) symsec->contents;
strtab = (const char *) strsec->contents; strtab = (const char *) strsec->contents;
for (; rel < relend; ++rel) { for (; rel < relend; ++rel) {
Elf32_Sym *extsym; extsym = &symtab[ELF32_R_SYM(rel->r_info)];
struct arch_symbol *intsym;
const char *name;
switch (ELF32_R_TYPE(rel->r_info)) { switch (ELF32_R_TYPE(rel->r_info)) {
#if defined(__sh__) #if defined(__arm__)
case R_SH_GOTPC: case R_ARM_GOT32:
case R_SH_GOTOFF: #elif defined(__sh__)
#else
case R_386_GOTPC:
case R_386_GOTOFF:
#endif
gotneeded = 1;
default:
continue;
#if defined(__sh__)
case R_SH_GOT32: case R_SH_GOT32:
#else #elif defined(__i386__)
case R_386_GOT32: case R_386_GOT32:
#endif #endif
break; break;
#if defined(__arm__)
case R_ARM_PC24:
case R_ARM_PLT32:
pltneeded = 1;
break;
case R_ARM_GOTPC:
case R_ARM_GOTOFF:
gotneeded = 1;
if (got_offset == 0)
got_offset = 4;
#elif defined(__sh__)
case R_SH_GOTPC:
case R_SH_GOTOFF:
gotneeded = 1;
#elif defined(__i386__)
case R_386_GOTPC:
case R_386_GOTOFF:
gotneeded = 1;
#endif
default:
continue;
} }
extsym = &symtab[ELF32_R_SYM(rel->r_info)]; if (extsym->st_name != 0) {
if (extsym->st_name)
name = strtab + extsym->st_name; name = strtab + extsym->st_name;
else } else {
name = f->sections[extsym->st_shndx]->name; name = f->sections[extsym->st_shndx]->name;
intsym = }
(struct arch_symbol *) obj_find_symbol(&ifile->root, name); intsym = (struct arch_symbol *) obj_find_symbol(f, name);
if (!intsym->gotent.offset_done) { if (!intsym->gotent.offset_done) {
intsym->gotent.offset_done = 1; intsym->gotent.offset_done = 1;
intsym->gotent.offset = offset; intsym->gotent.offset = got_offset;
offset += 4; got_offset += 4;
} }
#if defined(__arm__)
if (pltneeded && intsym->pltent.allocated == 0) {
intsym->pltent.allocated = 1;
intsym->pltent.offset = plt_offset;
plt_offset += 8;
intsym->pltent.inited = 0;
pltneeded = 0;
}
#endif
} }
} }
if (offset > 0 || gotneeded) #if defined(__arm__)
ifile->got = if (got_offset) {
obj_create_alloced_section(&ifile->root, ".got", 4, offset); struct obj_section* relsec = obj_find_section(f, ".got");
if (relsec) {
obj_extend_section(relsec, got_offset);
} else {
relsec = obj_create_alloced_section(f, ".got", 8, got_offset);
assert(relsec);
}
ifile->got = relsec;
}
if (plt_offset)
ifile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
#else
if (got_offset > 0 || gotneeded)
ifile->got = obj_create_alloced_section(f, ".got", 4, got_offset);
#endif
return 1; return 1;
} }
@ -1598,7 +1704,7 @@ old_init_module(const char *m_name, struct obj_file *f,
ksym->name = ksym->name =
(unsigned long) str - (unsigned long) symtab; (unsigned long) str - (unsigned long) symtab;
str = stpcpy(str, sym->name) + 1; str = strcpy(str, sym->name) + 1;
ksym++; ksym++;
} }
} }
@ -2201,8 +2307,9 @@ new_init_module(const char *m_name, struct obj_file *f,
#define new_init_module(x, y, z) TRUE #define new_init_module(x, y, z) TRUE
#define new_create_this_module(x, y) 0 #define new_create_this_module(x, y) 0
#define new_create_module_ksymtab(x) #define new_create_module_ksymtab(x)
#define query_module(v, w, x, y, z) -1
#endif /* BB_FEATURE_INSMOD_OLD_KERNEL */ #endif /* BB_FEATURE_INSMOD_NEW_KERNEL */
/*======================================================================*/ /*======================================================================*/
@ -2372,8 +2479,12 @@ void obj_allocate_commons(struct obj_file *f)
for (i = 0; i < f->header.e_shnum; ++i) { for (i = 0; i < f->header.e_shnum; ++i) {
struct obj_section *s = f->sections[i]; struct obj_section *s = f->sections[i];
if (s->header.sh_type == SHT_NOBITS) { if (s->header.sh_type == SHT_NOBITS) {
if (s->header.sh_size != 0)
s->contents = memset(xmalloc(s->header.sh_size), s->contents = memset(xmalloc(s->header.sh_size),
0, s->header.sh_size); 0, s->header.sh_size);
else
s->contents = NULL;
s->header.sh_type = SHT_PROGBITS; s->header.sh_type = SHT_PROGBITS;
} }
} }

View File

@ -5,6 +5,10 @@
* Copyright (C) 1999,2000 by Lineo, inc. * Copyright (C) 1999,2000 by Lineo, inc.
* Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
* *
* Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
* Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
* (which lack the query_module() interface).
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -32,9 +36,16 @@
#include <assert.h> #include <assert.h>
#include <getopt.h> #include <getopt.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/file.h>
#if !defined(BB_FEATURE_LSMOD_NEW_KERNEL) && !defined(BB_FEATURE_LSMOD_OLD_KERNEL)
#error "Must have ether BB_FEATURE_LSMOD_NEW_KERNEL or BB_FEATURE_LSMOD_OLD_KERNEL defined"
#endif
#ifdef BB_FEATURE_LSMOD_NEW_KERNEL
struct module_info struct module_info
{ {
unsigned long addr; unsigned long addr;
@ -120,3 +131,30 @@ extern int lsmod_main(int argc, char **argv)
return( 0); return( 0);
} }
#else /*BB_FEATURE_LSMOD_OLD_KERNEL*/
#if ! defined BB_FEATURE_USE_PROCFS
#error Sorry, I depend on the /proc filesystem right now.
#endif
extern int lsmod_main(int argc, char **argv)
{
int fd, i;
char line[128];
puts("Module Size Used by");
fflush(stdout);
if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) {
while ((i = read(fd, line, sizeof(line))) > 0) {
write(fileno(stdout), line, i);
}
close(fd);
return 0;
}
fatalError("/proc/modules: %s\n", strerror(errno));
return 1;
}
#endif /*BB_FEATURE_LSMOD_OLD_KERNEL*/