Date: Wed, 8 Jan 2003 16:56:30 +0100 (CET) From: Hartmut Brandt <brandt@fokus.gmd.de> To: FreeBSD-gnats-submit@FreeBSD.org Subject: sparc64/46870: loader does not resolve module dependencies Message-ID: <200301081556.h08FuUGE000695@catssrv.fokus.gmd.de>
next in thread | raw e-mail | index | archive | help
>Number: 46870
>Category: sparc64
>Synopsis: loader does not resolve module dependencies
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-sparc
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Wed Jan 08 08:00:00 PST 2003
>Closed-Date:
>Last-Modified:
>Originator: Hartmut Brandt
>Release: FreeBSD 5.0-CURRENT sparc64
>Organization:
FhI Fokus
>Environment:
System: FreeBSD catssrv.fokus.gmd.de 5.0-CURRENT FreeBSD 5.0-CURRENT #3: Tue Jan 7 18:15:41 CET 2003 root@catssrv.fokus.gmd.de:/opt/obj/usr/src/sys/CATSSRV sparc64
>Description:
The boot loader does not resolve module dependencies and does not load
modules upon which a given module depends.
>How-To-Repeat:
Build if_hme.ko and insert the following line into /boot/loader.conf:
if_hme_load="YES"
Reboot and observe the loader to load if_hme.ko but not miibus.ko. Observe
further that the kernel later on reports a missing dependency of hme on
miibus.
>Fix:
The problem is the same as with kldxref and the kernel linker: the loader
fails to process relocation correctly by assuming that only REL records exist.
The correct fix is to have machine dependent relocation routines call from
load_elf.c. This is somewhat complicated by the fact, that load_elf itself
is called via a machine dependent function pointer.
The attached patch is
a hack rather than a fix. Based on the precedent of an #ifdef __i386__
in load_elf.c, MD processing is done for __sparc__ in load_elf.c to do
just enough relocation processing to correctly access dependency information.
Note, that this does not really relocate the loaded image - this is done later
in the kernel linker. Instead local copies of the pointers are relocated.
Index: load_elf.c
===================================================================
RCS file: /usr/ncvs/src/sys/boot/common/load_elf.c,v
retrieving revision 1.24
diff -c -r1.24 load_elf.c
*** load_elf.c 10 May 2002 01:20:37 -0000 1.24
--- load_elf.c 8 Jan 2003 15:47:10 -0000
***************
*** 52,57 ****
--- 52,61 ----
Elf_Hashelt nchains;
Elf_Hashelt *buckets;
Elf_Hashelt *chains;
+ #ifdef __sparc__
+ Elf_Rela *rela;
+ size_t relasz;
+ #endif
char *strtab;
size_t strsz;
int fd;
***************
*** 63,68 ****
--- 67,76 ----
static int elf_loadimage(struct preloaded_file *mp, elf_file_t ef, vm_offset_t loadaddr);
static int elf_lookup_symbol(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym);
+ #ifdef __sparc__
+ static void elf_reloc_ptr(struct preloaded_file *mp, elf_file_t ef,
+ void *p, void *val, size_t len);
+ #endif
static int elf_parse_modmetadata(struct preloaded_file *mp, elf_file_t ef);
static char *fake_modname(const char *name);
***************
*** 491,496 ****
--- 499,512 ----
case DT_SYMTAB:
ef->symtab = (Elf_Sym*)(dp[i].d_un.d_ptr + off);
break;
+ #ifdef __sparc__
+ case DT_RELA:
+ ef->rela = (Elf_Rela *)(dp[i].d_un.d_ptr + off);
+ break;
+ case DT_RELASZ:
+ ef->relasz = dp[i].d_un.d_val;
+ break;
+ #endif
default:
break;
}
***************
*** 566,591 ****
--- 582,628 ----
modcnt = 0;
while (p < p_stop) {
+ #ifdef __sparc__
+ COPYOUT(p, &v, sizeof(v));
+ elf_reloc_ptr(fp, ef, p, &v, sizeof(v));
+ COPYOUT(v, &md, sizeof(md));
+ elf_reloc_ptr(fp, ef, v, &md, sizeof(md));
+ p++;
+ #else
COPYOUT(p++, &v, sizeof(v));
COPYOUT(v + ef->off, &md, sizeof(md));
+ #endif
switch(md.md_type) {
case MDT_DEPEND:
if (ef->kernel) /* kernel must not depend on anything */
break;
+ #ifdef __sparc__
+ s = strdupout((vm_offset_t)md.md_cval);
+ #else
s = strdupout((vm_offset_t)(md.md_cval + ef->off));
+ #endif
minfolen = sizeof(*mdepend) + strlen(s) + 1;
mdepend = malloc(minfolen);
if (mdepend == NULL)
return ENOMEM;
+ #ifdef __sparc__
+ COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend));
+ #else
COPYOUT((vm_offset_t)(md.md_data + ef->off), mdepend, sizeof(*mdepend));
+ #endif
strcpy((char*)(mdepend + 1), s);
free(s);
file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend);
free(mdepend);
break;
case MDT_VERSION:
+ #ifdef __sparc__
+ s = strdupout((vm_offset_t)md.md_cval);
+ COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
+ #else
s = strdupout((vm_offset_t)(md.md_cval + ef->off));
COPYOUT((vm_offset_t)(md.md_data + ef->off), &mver, sizeof(mver));
+ #endif
file_addmodule(fp, s, mver.mv_version, NULL);
free(s);
modcnt++;
***************
*** 657,659 ****
--- 694,723 ----
}
return ENOENT;
}
+
+ #ifdef __sparc__
+ /*
+ * Apply any intra-module relocations to the value. *p is the load address
+ * of the value and val/len is the value to be modified. This does NOT modify
+ * the image in-place, because this is done by kern_linker later on.
+ */
+ static void
+ elf_reloc_ptr(struct preloaded_file *mp, elf_file_t ef,
+ void *p, void *val, size_t len)
+ {
+ Elf_Addr off = (Elf_Addr)p - ef->off, word;
+ size_t n;
+ Elf_Rela r;
+
+ for (n = 0; n < ef->relasz / sizeof(r); n++) {
+ COPYOUT(ef->rela + n, &r, sizeof(r));
+
+ if (r.r_offset >= off && r.r_offset < off + len &&
+ ELF_R_TYPE(r.r_info) == R_SPARC_RELATIVE) {
+ word = ef->off + r.r_addend;
+ bcopy(&word, (char *)val + (r.r_offset - off),
+ sizeof(word));
+ }
+ }
+ }
+ #endif
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-sparc" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200301081556.h08FuUGE000695>
