Allow modules in ROM
From: Pavel Roskin
ChangeLog:
* include/grub/dl.h: Include grub/elf.h.
(struct grub_dl): Add symtab field.
* kern/dl.c [GRUB_MACHINE_QEMU]: Define
GRUB_MODULES_MACHINE_READONLY.
(grub_dl_resolve_symbols): Populate mod->symtab, making a copy
of the header for read-only modules.
(grub_dl_unload): Free mod->symtab for read-only modules.
* kern/i386/dl.c: Use mod->symtab.
* kern/powerpc/dl.c: Likewise.
* kern/sparc64/dl.c: Likewise.
* kern/x86_64/dl.c: Likewise.
---
include/grub/dl.h | 4 +++-
kern/dl.c | 19 +++++++++++++++++--
kern/i386/dl.c | 4 +---
kern/powerpc/dl.c | 4 +---
kern/sparc64/dl.c | 4 +---
kern/x86_64/dl.c | 4 +---
6 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 894da1d..bebb810 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -1,7 +1,7 @@
/* dl.h - types and prototypes for loadable module support */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2004,2005,2007,2008 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#define GRUB_MOD_INIT(name) \
static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \
@@ -78,6 +79,7 @@ struct grub_dl
int ref_count;
grub_dl_dep_t dep;
grub_dl_segment_t segment;
+ Elf_Sym *symtab;
void (*init) (struct grub_dl *mod);
void (*fini) (void);
};
diff --git a/kern/dl.c b/kern/dl.c
index cd34e31..af4e5aa 100644
--- a/kern/dl.c
+++ b/kern/dl.c
@@ -1,7 +1,7 @@
/* dl.c - loadable module support */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,12 @@
#include
#include
#include
+#include
+
+/* Platforms where modules are in a readonly area of memory. */
+#if defined(GRUB_MACHINE_QEMU)
+#define GRUB_MODULES_MACHINE_READONLY
+#endif
@@ -309,7 +315,13 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symbol table");
- sym = (Elf_Sym *) ((char *) e + s->sh_offset);
+#ifdef GRUB_MODULES_MACHINE_READONLY
+ mod->symtab = grub_malloc (s->sh_size);
+ memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
+#else
+ mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
+#endif
+ sym = mod->symtab;
size = s->sh_size;
entsize = s->sh_entsize;
@@ -671,6 +683,9 @@ grub_dl_unload (grub_dl_t mod)
}
grub_free (mod->name);
+#ifdef GRUB_MODULES_MACHINE_READONLY
+ grub_free (mod->symtab);
+#endif
grub_free (mod);
return 1;
}
diff --git a/kern/i386/dl.c b/kern/i386/dl.c
index 978bfb1..a17f175 100644
--- a/kern/i386/dl.c
+++ b/kern/i386/dl.c
@@ -43,7 +43,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf32_Shdr *s;
- Elf32_Sym *symtab;
Elf32_Word entsize;
unsigned i;
@@ -57,7 +56,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
- symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
@@ -89,7 +87,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
"reloc offset is out of the segment");
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
- sym = (Elf32_Sym *) ((char *) symtab
+ sym = (Elf32_Sym *) ((char *) mod->symtab
+ entsize * ELF32_R_SYM (rel->r_info));
switch (ELF32_R_TYPE (rel->r_info))
diff --git a/kern/powerpc/dl.c b/kern/powerpc/dl.c
index ae987c0..9b1cb14 100644
--- a/kern/powerpc/dl.c
+++ b/kern/powerpc/dl.c
@@ -44,7 +44,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf32_Shdr *s;
- Elf32_Sym *symtab;
Elf32_Word entsize;
unsigned i;
@@ -58,7 +57,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
- symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
@@ -91,7 +89,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
"reloc offset is out of the segment");
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
- sym = (Elf32_Sym *) ((char *) symtab
+ sym = (Elf32_Sym *) ((char *) mod->symtab
+ entsize * ELF32_R_SYM (rel->r_info));
/* On the PPC the value does not have an explicit
diff --git a/kern/sparc64/dl.c b/kern/sparc64/dl.c
index d998daf..5334896 100644
--- a/kern/sparc64/dl.c
+++ b/kern/sparc64/dl.c
@@ -44,7 +44,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf64_Ehdr *e = ehdr;
Elf64_Shdr *s;
- Elf64_Sym *symtab;
Elf64_Word entsize;
unsigned i;
@@ -58,7 +57,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
- symtab = (Elf64_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
@@ -91,7 +89,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
"reloc offset is out of the segment");
addr = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
- sym = (Elf64_Sym *) ((char *) symtab
+ sym = (Elf64_Sym *) ((char *) mod->symtab
+ entsize * ELF64_R_SYM (rel->r_info));
value = sym->st_value + rel->r_addend;
diff --git a/kern/x86_64/dl.c b/kern/x86_64/dl.c
index a606901..9e5de6e 100644
--- a/kern/x86_64/dl.c
+++ b/kern/x86_64/dl.c
@@ -43,7 +43,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf64_Ehdr *e = ehdr;
Elf64_Shdr *s;
- Elf64_Sym *symtab;
Elf64_Word entsize;
unsigned i;
@@ -57,7 +56,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
- symtab = (Elf64_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
@@ -91,7 +89,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
addr64 = (Elf64_Xword *) addr32;
- sym = (Elf64_Sym *) ((char *) symtab
+ sym = (Elf64_Sym *) ((char *) mod->symtab
+ entsize * ELF64_R_SYM (rel->r_info));
switch (ELF64_R_TYPE (rel->r_info))