summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-10-01 10:20:57 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2007-10-01 10:20:57 +0200
commit6b58e74d04e651cb3adf6986a009e68abcb07901 (patch)
tree55c8ad848d6a28dbd715fe83bcdb203d317d0665
parent8b8c95b9fccb86eca260684c597b85ab1882a9ce (diff)
downloadbarebox-6b58e74d04e651cb3adf6986a009e68abcb07901.tar.gz
barebox-6b58e74d04e651cb3adf6986a009e68abcb07901.tar.xz
Resolve the symbols using an extra section and only resolve explicitly
exported symbols. Using kallsyms for this purpose doesn't do it because kallsyms do not resolve variables. Also the symbol table gets quite big using kallsyms.
-rw-r--r--common/module.c65
-rw-r--r--include/asm-generic/u-boot.lds.h2
-rw-r--r--include/module.h28
3 files changed, 91 insertions, 4 deletions
diff --git a/common/module.c b/common/module.c
index 65f0ad0da5..0985567850 100644
--- a/common/module.c
+++ b/common/module.c
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define DEBUG
#include <common.h>
#include <errno.h>
@@ -27,15 +28,54 @@
#include <fs.h>
#include <kallsyms.h>
+static unsigned int find_sec(Elf_Ehdr *hdr,
+ Elf_Shdr *sechdrs,
+ const char *secstrings,
+ const char *name, int nlen)
+{
+ unsigned int i;
+
+ for (i = 1; i < hdr->e_shnum; i++)
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)) {
+ if (nlen && !strncmp(secstrings+sechdrs[i].sh_name, name, nlen))
+ return i;
+ if (!nlen && !strcmp(secstrings+sechdrs[i].sh_name, name))
+ return i;
+ }
+ return 0;
+}
+
+/* Provided by the linker */
+extern const struct kernel_symbol __u_boot_symtab_start[];
+extern const struct kernel_symbol __u_boot_symtab_end[];
+
+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+ const struct kernel_symbol *start,
+ const struct kernel_symbol *stop)
+{
+ const struct kernel_symbol *ks = start;
+ for (; ks < stop; ks++) {
+ printf("name: %s\n", ks->name);
+ if (strcmp(ks->name, name) == 0)
+ return ks;
+ }
+ return NULL;
+}
+
static unsigned long resolve_symbol(Elf32_Shdr *sechdrs,
const char *name)
{
- unsigned long ret;
+ const struct kernel_symbol *ks;
debug("%s: %s\n", __FUNCTION__, name);
- ret = kallsyms_lookup_name(name);
+ ks = lookup_symbol(name, __u_boot_symtab_start,
+ __u_boot_symtab_end);
- return ret;
+ if (ks)
+ return ks->value;
+ return 0;
}
/* Change all symbols so that sh_value encodes the pointer directly. */
@@ -157,6 +197,7 @@ struct module * load_module(void *mod_image, unsigned long len)
char *secstrings;
void *ptr = NULL;
int err;
+ int cmdindex;
if (len < sizeof(*ehdr))
return NULL;
@@ -243,6 +284,22 @@ struct module * load_module(void *mod_image, unsigned long len)
numsyms = sechdrs[symindex].sh_size / sizeof(Elf32_Sym);
sym = (void *)sechdrs[symindex].sh_addr;
+ /*
+ * FIXME: in .o files we have the command structs in the
+ * .u_boot_cmd_<name> section to be able to let the linker
+ * sort the commands alphabetically. When using the .o files
+ * as modules this is bad because we have the commands in different
+ * sections. So we probably need a linking stage for modules to
+ * put the different sections back into a single one.
+ *
+ * For now we only find the _first_ command in a module.
+ */
+ cmdindex = find_sec(ehdr, sechdrs, secstrings,
+ MODULE_SYMBOL_PREFIX ".u_boot_cmd_", 12);
+ if (cmdindex) {
+ register_command((void *)sechdrs[cmdindex].sh_addr);
+ }
+
for (i = 0; i < numsyms; i++) {
if (!strcmp(strtab + sym[i].st_name, MODULE_SYMBOL_PREFIX "init_module")) {
printf("found init_module() at 0x%08x\n", sym[i].st_value);
@@ -274,7 +331,7 @@ static int do_insmod (cmd_tbl_t *cmdtp, int argc, char *argv[])
buf = read_file(argv[1], &len);
if (!buf) {
- printf("error\n");
+ perror("insmod");
return 1;
}
diff --git a/include/asm-generic/u-boot.lds.h b/include/asm-generic/u-boot.lds.h
index e8e9ce1276..f01fc84cd3 100644
--- a/include/asm-generic/u-boot.lds.h
+++ b/include/asm-generic/u-boot.lds.h
@@ -10,3 +10,5 @@
*(.initcall.7)
#define U_BOOT_CMDS *(SORT_BY_NAME(.u_boot_cmd*))
+
+#define U_BOOT_SYMS *(__u_boot_symtab)
diff --git a/include/module.h b/include/module.h
index faea2ae7e4..421b9374fb 100644
--- a/include/module.h
+++ b/include/module.h
@@ -4,6 +4,34 @@
#include <elf.h>
#include <asm/module.h>
+#ifndef MODULE_SYMBOL_PREFIX
+#define MODULE_SYMBOL_PREFIX
+#endif
+
+#ifdef CONFIG_MODULE
+struct kernel_symbol
+{
+ unsigned long value;
+ const char *name;
+};
+
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define __EXPORT_SYMBOL(sym, sec) \
+ extern typeof(sym) sym; \
+ static const char __u_boot_strtab_##sym[] \
+ __attribute__((section("__u_boot_symtab_strings"))) \
+ = MODULE_SYMBOL_PREFIX #sym; \
+ static const struct kernel_symbol __u_boot_symtab_##sym \
+ __used \
+ __attribute__((section("__u_boot_symtab" sec), unused)) \
+ = { (unsigned long)&sym, __u_boot_strtab_##sym }
+
+#define EXPORT_SYMBOL(sym) \
+ __EXPORT_SYMBOL(sym, "")
+#else
+#define EXPORT_SYMBOL(sym)
+#endif
+
struct module {
char *name;