diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 1736686dfdc57731e0367a09944c8b1bd44f8139..23831146aa51867aec5c172ad2cb1e68a2c4a2fd 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -16,11 +16,12 @@
  * @param m an ELF module
  * @param rel an ELF relocation entry
  * @param sym the address of the target symbol
+ * @param sec_name the name of the section to apply the relocation in
  *
  * return 0 on success
  */
 
-int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym)
+int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym, const char *sec_name)
 {
 	Elf_Addr rsym;
 
@@ -40,9 +41,13 @@ int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym)
 	if (!sym)
 		return -EINVAL;
 
+	if (!sec_name) {
+		pr_err("\tsec_name empty!\n");
+		return -EINVAL;
+	}
 
 
-	text = find_mod_sec(m, ".text");
+	text = find_mod_sec(m, sec_name);
 
 	loc8  = (uint8_t  *) (text->addr + rel->r_offset);
 	loc32 = (uint32_t *) loc8;
diff --git a/arch/sparc/kernel/ttable.S b/arch/sparc/kernel/ttable.S
index 9ee891551c42fcc89d772864865df66c3f80bc8c..8cd0e19ecebc72804f654b96841a6c1790db18ea 100644
--- a/arch/sparc/kernel/ttable.S
+++ b/arch/sparc/kernel/ttable.S
@@ -145,8 +145,6 @@ hw_div0_trap_handler:
 nmi_entry:
 	.global reg_access_trap_handler
 reg_access_trap_handler:
-	.global strchr
-strchr:
 	.global syscall_tbl
 syscall_tbl:
 	.global syscall_trap
@@ -159,4 +157,4 @@ syscall_trap:
 unimpl_flush_trap_handler:
 	.global watchpoint_det_trap_handler
 watchpoint_det_trap_handler:
-	ta 0
+	ta 3
diff --git a/include/kernel/elf.h b/include/kernel/elf.h
index 4797c137df8986f1d7515d7a5636ff7352fa3a01..79739dc17a5860b2105df7e144020265e3e68a0a 100644
--- a/include/kernel/elf.h
+++ b/include/kernel/elf.h
@@ -568,6 +568,9 @@ int elf_header_check(Elf_Ehdr *ehdr);
 Elf_Shdr *elf_get_shdr(const Elf_Ehdr *ehdr);
 size_t elf_find_shdr_alloc_idx(const Elf_Ehdr *ehdr, const size_t offset);
 
+size_t elf_get_common_size(const Elf_Ehdr *ehdr);
+size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname);
+
 Elf_Shdr *elf_get_sec_by_idx(const Elf_Ehdr *ehdr, const size_t idx);
 Elf_Shdr *elf_get_sec_shstrtab(const Elf_Ehdr *ehdr);
 char *elf_get_shstrtab_str(const Elf_Ehdr *ehdr, size_t idx);
@@ -586,6 +589,7 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr,
 				   const char *name, unsigned long *value);
 
 unsigned long elf_get_symbol_type(const Elf_Ehdr *ehdr, const char *name);
+size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name);
 
 size_t elf_find_sec_idx_by_type(const Elf_Ehdr *ehdr,
 				const uint32_t sh_type,
@@ -606,4 +610,6 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr);
 void elf_dump_sections(const Elf_Ehdr *ehdr);
 
 
+unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr,
+				    const char *name);
 #endif /* _KERNEL_ELF_H_ */
diff --git a/include/kernel/module.h b/include/kernel/module.h
index e357eaff481c85521a2b49b71aa8778a5de4185b..dc3584dcfa22484926021594c3b8d11252bc1ec9 100644
--- a/include/kernel/module.h
+++ b/include/kernel/module.h
@@ -62,7 +62,8 @@ struct elf_module {
 
 
 /* implemented in architecture code */
-int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym);
+int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym,
+		      const char *sec_name);
 
 
 struct module_section *find_mod_sec(const struct elf_module *m,
diff --git a/include/kernel/string.h b/include/kernel/string.h
index b39f37523bffa2953d379057cc8afc830e2ef02e..532d0db8ac84ebde948b1ccf237090c8d2b49317 100644
--- a/include/kernel/string.h
+++ b/include/kernel/string.h
@@ -20,12 +20,16 @@ char *strpbrk(const char *s, const char *accept);
 char *strsep(char **stringp, const char *delim);
 char *strdup(const char *s);
 
+char *strchr(const char *s, int c);
+
 char *strstr(const char *haystack, const char *needle);
 size_t strlen(const char *s);
 int memcmp(const void *s1, const void *s2, size_t n);
 
 void *memset(void *s, int c, size_t n);
 void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+
 char *strcpy(char *dest, const char *src);
 void bzero(void *s, size_t n);
 
@@ -46,5 +50,7 @@ int vprintf(const char *format, va_list ap);
 int vsprintf(char *str, const char *format, va_list ap);
 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
 
+int puts(const char *s);
+int putchar(int c);
 
 #endif /* _KERNEL_STRING_H_ */
diff --git a/init/Kconfig b/init/Kconfig
index a786cac7cdaa4d70deae7d609f7b41398986da98..63b9260acc7ad60188778b86f413db61e4e14120 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -105,6 +105,16 @@ config EMBED_MODULES_IMAGE
 	  generated modules into the final kernel binary.
 	  This is a convenience option, if unsure, say Y.
 
+config EMBED_APPLICATION
+	string "Embed an application image"
+	depends on EMBED_MODULES_IMAGE
+	default ""
+	help
+	  Specify a path to an executable to embed or leave it empty.
+	  Note: in the current implementation, the executable is treated as a
+	  kernel module, so it requires to be relocatible and have a init/exit
+	  call.
+
 endif # MODULES
 
 
@@ -178,4 +188,5 @@ config DEBUG_INFO_REDUCED
 	  DEBUG_INFO build and compile times are reduced too.
 	  Only works with newer gcc versions.
 
+
 endmenu
diff --git a/init/main.c b/init/main.c
index 063716fd7b80e03b762381008559668ef50a1aac..eb3bb2f86e414c7c92dc083d706fe86788ffd2c6 100644
--- a/init/main.c
+++ b/init/main.c
@@ -163,6 +163,27 @@ int kernel_main(void)
 	modules_list_loaded();
 #endif
 
+
+#ifdef CONFIG_EMBED_APPLICATION
+	/* dummy demonstrator */
+{
+	void *addr;
+	struct elf_module m;
+
+	addr = module_read_embedded("CrApp1");
+
+	pr_debug(MSG "test executable address is %p\n", addr);
+	if (addr)
+		module_load(&m, addr);
+
+#if 0
+	modules_list_loaded();
+#endif
+}
+#endif
+
+
+
 #ifdef CONFIG_MPPB
 	/* The mppbv2 LEON's cache would really benefit from cache sniffing...
 	 * Interactions with DMA or Xentiums are a pain when using the lower
diff --git a/kernel/module.c b/kernel/module.c
index b15a5d7893e3b3e8c99ad0bbf4deb3884524b867..aab0150f8a7decccb0c20a88faedc25b4fe44b04 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -69,6 +69,28 @@ struct module_section *find_mod_sec(const struct elf_module *m,
 }
 
 
+/**
+ * @brief find module section by index
+ *
+ * @param m a struct elf_module
+ *
+ * @param idx the index of the module section
+ *
+ * @return module section structure pointer or NULL if not found
+ */
+
+struct module_section *find_mod_idx(const struct elf_module *m,
+				    size_t idx)
+
+{
+	if (idx >= m->num_sec)
+		return NULL;
+
+	return &m->sec[idx];
+}
+
+
+
 /**
  * @brief setup the module structure
  *
@@ -178,8 +200,13 @@ static int module_load_mem(struct elf_module *m)
 		sec = elf_get_sec_by_idx(m->ehdr, idx);
 
 
+#if 0
 		if (!sec->sh_size)	/* don't need those */
 			continue;
+#else
+		if (!(sec->sh_flags & SHF_ALLOC))
+			continue;
+#endif
 
 		s->size = sec->sh_size;
 
@@ -193,24 +220,27 @@ static int module_load_mem(struct elf_module *m)
 			goto error;
 
 		strcpy(s->name, src);
+		
+		pr_err(MOD "section %s index %d max %d\n", s->name, s, m->num_sec);
 
 
 		if (sec->sh_type & SHT_NOBITS) {
-			pr_debug(MOD "\tZero segment %10s at %p size %ld\n",
+			pr_info(MOD "\tZero segment %10s at %p size %ld\n",
 			       s->name, (char *) va_load,
 			       sec->sh_size);
 
 			bzero((void *) va_load, s->size);
 		} else {
-			pr_debug(MOD "\tCopy segment %10s from %p to %p size %ld\n",
+			pr_info(MOD "\tCopy segment %10s from %p to %p size %ld\n",
 			       s->name,
 			       (char *) m->ehdr + sec->sh_offset,
 			       (char *) va_load,
 			       sec->sh_size);
 
-			memcpy((void *) va_load,
-			       (char *) m->ehdr + sec->sh_offset,
-			       sec->sh_size);
+			if (sec->sh_size)
+				memcpy((void *) va_load,
+				       (char *) m->ehdr + sec->sh_offset,
+				       sec->sh_size);
 		}
 
 		s->addr = va_load;
@@ -219,10 +249,84 @@ static int module_load_mem(struct elf_module *m)
 		s++;
 
 		if (s > &m->sec[m->num_sec]) {
-			pr_debug(MOD "Error out of section memory\n");
+			pr_err(MOD "Error out of section memory\n");
+			goto error;
+		}
+	}
+
+#if 0
+	if (elf_get_common_size(m->ehdr)) {
+
+		m->num_sec++;
+		m->sec = (struct module_section *)
+			krealloc(m->sec, sizeof(struct module_section) * m->num_sec);
+
+		if (!m->sec)
+			goto error;
+
+		s = &m->sec[m->num_sec - 1];
+
+		s->size = elf_get_common_size(m->ehdr);
+		s->addr = (unsigned long) kzalloc(s->size);
+		if (!s->addr)
+			goto error;
+
+		pr_info(MOD "\tcreating .alloc section of %d bytes at %x\n", s->size, s->addr);
+
+		s->name = kmalloc(strlen(".alloc"));
+		if (!s->name)
+			goto error;
+
+		strcpy(s->name, ".alloc");
+
+	}
+#else
+	/* yes, yes, fixup like everything else here */
+	if (elf_get_common_objects(m->ehdr, NULL)) {
+		size_t cnt = elf_get_common_objects(m->ehdr, NULL);
+		char **obj;
+
+		m->sec = (struct module_section *)
+			krealloc(m->sec, sizeof(struct module_section) * (m->num_sec + cnt));
+
+		if (!m->sec)
 			goto error;
+
+
+		/* point to last */
+		s = &m->sec[m->num_sec];
+		/* and update */
+		m->num_sec += cnt;
+
+		obj = kmalloc(cnt * sizeof(char **));
+		if (!obj)
+			goto error;
+		/* load names */
+		elf_get_common_objects(m->ehdr, obj);
+
+
+		/* Allocate one section entry for each object, this is not
+		 * that efficient, but what the heck. Better not to have
+		 * uninitialised non-static globals at all!
+		 */
+		for (idx = 0; idx < cnt; idx++) {
+			s->size = elf_get_symbol_size(m->ehdr, obj[idx]);
+			s->addr = (unsigned long) kzalloc(s->size);
+			if (!s->addr)
+				goto error;
+			pr_debug(MOD "\tcreating \"%s\" section of %d bytes at %x\n", obj[idx], s->size, s->addr);
+			s->name = kmalloc(strlen(obj[idx]));
+			if (!s->name)
+				goto error;
+			strcpy(s->name, obj[idx]);
+			s++;
 		}
+
+		kfree(obj);
 	}
+#endif
+
+
 
 	return 0;
 
@@ -264,11 +368,12 @@ static int module_relocate(struct elf_module *m)
 		if (m->ehdr->e_type != ET_DYN)
 			return 0;
 
-
 	/* we only need RELA type relocations */
 
 	while (1) {
 
+		char *rel_sec;
+
 		idx = elf_find_sec_idx_by_type(m->ehdr, SHT_RELA, idx + 1);
 
 		if (!idx)
@@ -276,8 +381,16 @@ static int module_relocate(struct elf_module *m)
 
 		sec = elf_get_sec_by_idx(m->ehdr, idx);
 
-		pr_debug(MOD "\n"
-			MOD "Section Header info: %ld\n", sec->sh_info);
+		pr_info(MOD "\n"
+			MOD "Section Header info: %ld %s\n", sec->sh_info, elf_get_shstrtab_str(m->ehdr, idx));
+
+		if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.text"))
+			rel_sec = ".text";
+		else if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.data"))
+			rel_sec = ".data";
+		else
+			BUG();
+
 
 		if (sec) {
 
@@ -295,8 +408,8 @@ static int module_relocate(struct elf_module *m)
 				unsigned int symsec = ELF_R_SYM(relatab[i].r_info);
 				char *symstr = elf_get_symbol_str(m->ehdr, symsec);
 				struct module_section *s;
-				struct module_section *text  = find_mod_sec(m, ".text");
-				
+				struct module_section *text  = find_mod_sec(m, ".text"); /* ?? rel_sec ?? */
+
 				pr_debug(MOD "OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n",
 				       relatab[i].r_offset,
 				       relatab[i].r_info,
@@ -308,23 +421,63 @@ static int module_relocate(struct elf_module *m)
 
 
 				if (strlen(symstr)) {
-					Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr);
+						unsigned long symval;
+						Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr);
 
-					if (!sym) {
+						if (!sym) {
+							pr_debug(MOD "\tSymbol %s not found in library, trying to resolving in module\n",
+								 symstr);
 
-						unsigned long symval;
-						pr_info(MOD "\tSymbol %s not found in library, trying to resolving in module\n",
-							 symstr);
+							if ((elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) {
+								char *secstr;
 
 
-						if (!(elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) {
-							pr_debug(MOD "\tERROR, object data resolution not yet implemented, symbol %s may not function as intended. If it is a variable, declare it static as a workaround\n", symstr);
-						}
 
+								s = find_mod_sec(m, elf_get_shstrtab_str(m->ehdr, elf_get_symbol_shndx(m->ehdr, symstr)));
+
+								switch (elf_get_symbol_shndx(m->ehdr, symstr)) {
+								case SHN_UNDEF:
+									pr_debug(MOD "\tundefined section index\n");
+									break;
+								case SHN_ABS:
+									pr_debug(MOD "\tabsolute value section index\n");
+								case SHN_COMMON:
+							     		pr_debug(MOD "\t %s common symbol index (must allocate) add: %d\n", symstr,
+										relatab[i].r_addend);
+									s = find_mod_sec(m, symstr);
+									if (!s) {
+										pr_err("no suitable section found");
+										return -1;
+									}
+									break;
+								default:
+									break;
+
+								}
+
+
+								if (!s) {
+									pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr);
+									continue;
+								}
+								secstr = s->name;
+								/* target address to insert at location */
+								reladdr = (long) s->addr;
+							pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr);
+
+							/* needed ?? */
+							//elf_get_symbol_value(m->ehdr, symstr, (unsigned long *) &relatab[i].r_addend);
+								apply_relocate_add(m, &relatab[i], reladdr, rel_sec);
+								continue;
+
+							}
+
+#if 0
 						if (!(elf_get_symbol_type(m->ehdr, symstr) & (STT_FUNC | STT_OBJECT))) {
 							pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr);
 							return -1;
 						}
+#endif
 						if (!elf_get_symbol_value(m->ehdr, symstr, &symval)) {
 							pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr);
 							return -1;
@@ -334,25 +487,26 @@ static int module_relocate(struct elf_module *m)
 
 					}
 
-					pr_debug(MOD "\tSymbol %s at %lx\n", symstr, sym);
+					pr_debug(MOD "\tSymbol %s at %lx val %lx sec %d\n", symstr, sym, symval, symsec);
 
-					apply_relocate_add(m, &relatab[i], sym);
+					apply_relocate_add(m, &relatab[i], sym, rel_sec);
 
 				} else  { /* no string, symtab entry is probably a section, try to identify it */
 
 					char *secstr = elf_get_shstrtab_str(m->ehdr, symsec);
 
-					s = find_mod_sec(m, secstr);
+					s = find_mod_idx(m, symsec-1);
 
 					if (!s) {
 						pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr);
 							continue;
 					}
+					secstr = s->name;
 					/* target address to insert at location */
 					reladdr = (long) s->addr;
-					pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr);
+					pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr);
 
-					apply_relocate_add(m, &relatab[i], reladdr);
+					apply_relocate_add(m, &relatab[i], reladdr, rel_sec);
 				}
 
 				pr_debug(MOD "\n");
diff --git a/lib/elf.c b/lib/elf.c
index 89553fd1a52939164f1a9ea062d162c48b291eb0..df56bb6859a0b8f10b1b5f58484f1b1c86984e04 100644
--- a/lib/elf.c
+++ b/lib/elf.c
@@ -510,6 +510,102 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr,
 }
 
 
+/**
+ * @brief get the value of a symbol
+ *
+ * @param ehdr an Elf_Ehdr
+ *
+ * @param name the name of the symbol
+ *
+ * @return the size of the symbol (0 if not found or simply size 0)
+ *	   -1 on error
+ */
+
+size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name)
+
+{
+	unsigned int i;
+	size_t sym_cnt;
+
+	Elf_Shdr *symtab;
+	Elf_Sym *symbols;
+
+
+	symtab = elf_find_sec(ehdr, ".symtab");
+
+	if (!symtab) {
+		pr_debug(MSG "WARN: no .symtab section found\n");
+		return -1;
+	}
+
+	if (symtab->sh_entsize != sizeof(Elf_Sym)) {
+		pr_debug(MSG "Error %d != %ld\n",
+			 sizeof(Elf_Sym), symtab->sh_entsize);
+		return -1;
+	}
+
+	symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset);
+
+	sym_cnt = symtab->sh_size / symtab->sh_entsize;
+
+	for (i = 0; i < sym_cnt; i++) {
+		if(!strcmp(elf_get_symbol_str(ehdr, i), name))
+			return (size_t) symbols[i].st_size;
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief get the section index of a symbol
+ *
+ * @param ehdr an Elf_Ehdr
+ *
+ * @param name the name of the symbol
+ *
+ * @return the section index of the symbol or -1 if not found
+ */
+
+unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr,
+				    const char *name)
+
+{
+	unsigned int i;
+	size_t sym_cnt;
+
+	Elf_Shdr *symtab;
+	Elf_Sym *symbols;
+
+
+	symtab = elf_find_sec(ehdr, ".symtab");
+
+	if (!symtab) {
+		pr_debug(MSG "WARN: no .symtab section found\n");
+		return -1;
+	}
+
+	if (symtab->sh_entsize != sizeof(Elf_Sym)) {
+		pr_debug(MSG "Error %d != %ld\n",
+			 sizeof(Elf_Sym), symtab->sh_entsize);
+		return -1;
+	}
+
+	symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset);
+
+	sym_cnt = symtab->sh_size / symtab->sh_entsize;
+
+	for (i = 0; i < sym_cnt; i++) {
+		if(!strcmp(elf_get_symbol_str(ehdr, i), name)) {
+			return symbols[i].st_shndx;
+		}
+	}
+
+	return -1;
+}
+
+
+
 /**
  * @brief get the ELF type of a symbol
  *
@@ -607,14 +703,114 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr)
 	for (i = 0; i <ehdr->e_shnum; i++) {
 		shdr = elf_get_sec_by_idx(ehdr, i);
 		if ((shdr->sh_flags & SHF_ALLOC))
-			if (shdr->sh_size)
-				cnt++;
+			cnt++;
 	}
 
 	return cnt;
 }
 
 
+
+/* @brief get the total byte size of unallocated uninitialised common objects
+ *
+ * @param ehdr an Elf_Ehdr
+ *
+ * @return the number of bytes to be occupied by common (unallocated) objects
+ */
+
+size_t elf_get_common_size(const Elf_Ehdr *ehdr)
+{
+	unsigned int i;
+	size_t sym_cnt;
+
+
+	Elf_Shdr *symtab;
+	Elf_Sym *symbols;
+
+	size_t bytes = 0;
+
+
+	symtab = elf_find_sec(ehdr, ".symtab");
+
+	if (!symtab) {
+		pr_debug(MSG "WARN: no .symtab section found\n");
+		return 0;
+	}
+
+	if (symtab->sh_entsize != sizeof(Elf_Sym)) {
+		pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize);
+		return 0;
+	}
+
+	symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset);
+
+	sym_cnt = symtab->sh_size / symtab->sh_entsize;
+
+	for (i = 0; i < sym_cnt; i++) {
+		if (symbols[i].st_shndx == SHN_COMMON)
+			bytes += symbols[i].st_size;
+	}
+
+	return bytes;
+}
+
+
+/* @brief get the total count of unallocated uninitialised common objects
+ *
+ * @param ehdr an Elf_Ehdr
+ * @param[out] an index array
+ *
+ * @note set idx to NULL to determine the number of elements needed for the
+ *	 array
+ *
+ * @return the number of common objects
+ */
+
+size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname)
+{
+	unsigned int i;
+	size_t sym_cnt;
+
+
+	Elf_Shdr *symtab;
+	Elf_Sym *symbols;
+
+	size_t common = 0;
+
+
+	symtab = elf_find_sec(ehdr, ".symtab");
+
+	if (!symtab) {
+		pr_debug(MSG "WARN: no .symtab section found\n");
+		return 0;
+	}
+
+	if (symtab->sh_entsize != sizeof(Elf_Sym)) {
+		pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize);
+		return 0;
+	}
+
+	symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset);
+
+	sym_cnt = symtab->sh_size / symtab->sh_entsize;
+
+	for (i = 0; i < sym_cnt; i++) {
+		if (symbols[i].st_shndx == SHN_COMMON) {
+			if (objname)
+				objname[common] = elf_get_symbol_str(ehdr, i);
+			common++;
+		}
+	}
+
+	return common;
+}
+
+
+
+
+
+
+
 /**
  * @brief get the number of entries in a dynamic section
  *
@@ -727,7 +923,8 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr)
 	printk(MSG "\n"
 	       MSG ".symtab contains %d entries\n"
 	       MSG "============================\n"
-	       MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt);
+	       MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\t\t[SHIDX]\n",
+	       sym_cnt);
 
 
 	for (i = 0; i < sym_cnt; i++) {
@@ -756,7 +953,9 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr)
 			printk("\tUNKNOWN"); break;
 		}
 
-		printk("\t%-10s\n", elf_get_symbol_str(ehdr, i));
+		printk("\t%-10s", elf_get_symbol_str(ehdr, i));
+
+		printk("\t%4ld\n", symbols[i].st_shndx);
 
 	}
 }
diff --git a/lib/string.c b/lib/string.c
index 51a37bf7bd38099eaf22f0258f4a0488f5c4d023..2cf71210ef721e6d7a298b7dd0313c26ed77369d 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -173,6 +173,33 @@ char *strdup(const char *s)
 EXPORT_SYMBOL(strdup);
 
 
+/**
+ * @brief locate a character in string
+ *
+ * @param s the string to search in
+ * @param c the character to search for
+ *
+ * @returns a pointer to the first matched character or NULL if not found
+ *
+ * @note the terminating null byte is considered part of the string, so that if
+ *	 c is given as '\0', the function returns a pointer to the terminator
+ */
+
+char *strchr(const char *s, int c)
+{
+	while ((*s) != (char) c) {
+
+		if ((*s) == '\0')
+			return NULL;
+
+		s++;
+	}
+
+	return (char *) s;
+}
+EXPORT_SYMBOL(strchr);
+
+
 /**
  * @brief calculate the length of a string
  *
@@ -300,6 +327,53 @@ void *memcpy(void *dest, const void *src, size_t n)
 EXPORT_SYMBOL(memcpy);
 
 
+/**
+ * @brief copy a memory area src that may overlap with area dest
+ *
+ * @param dest the destination memory area
+ * @param src the source memory area
+ * @param n the number of bytes to copy
+ *
+ * @returns a pointer to dest
+ */
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+	char *d;
+
+	const char *s;
+
+	if (dest <= src) {
+
+		d = dest;
+		s = src;
+
+		while (n--) {
+			(*d) = (*s);
+			d++;
+			s++;
+		}
+
+	} else {
+
+		d = dest;
+		d += n;
+
+		s = src;
+		s += n;
+
+		while (n--) {
+			d--;
+			s--;
+			(*d) = (*s);
+		}
+
+	}
+	return dest;
+}
+EXPORT_SYMBOL(memmove);
+
+
 /**
  * @brief copy a '\0' terminated string
  *
@@ -352,6 +426,58 @@ void bzero(void *s, size_t n)
 EXPORT_SYMBOL(bzero);
 
 
+/**
+ * @brief writes the string s and a trailing newline to stdout
+ *
+ * @param str    the destination buffer
+ * @param format the format string buffer
+ * @param ...    arguments to the format string
+ *
+ * @return the number of characters written to buf
+ */
+
+int puts(const char *s)
+{
+	int n;
+
+	n = vsnprintf(NULL, INT_MAX, s, NULL);
+	n+= vsnprintf(NULL, INT_MAX, "\n", NULL);
+
+	return n;
+}
+EXPORT_SYMBOL(puts);
+
+
+/**
+ * @brief  writes the character c, cast to an unsigned char, to stdout
+ *
+ * @param c the character to write
+ *
+ * @return the number of characters written to buf
+ *
+ * FIXME: this must be replaced by a different mechanic, e.g. provided
+ *	  by the architecture or a driver
+ */
+
+int putchar(int c)
+{
+#define TREADY 4
+	static volatile int *console = (int *)0x80000100;
+
+	while (!(console[1] & TREADY));
+
+	console[0] = 0x0ff & c;
+
+	if (c == '\n') {
+		while (!(console[1] & TREADY));
+		console[0] = (int) '\r';
+	}
+
+	return c;
+}
+
+
+
 
 /**
  * @brief print a string into a buffer
diff --git a/scripts/link-leanos.sh b/scripts/link-leanos.sh
index db0f57a1cb85898593977e34b47939a1766e1e76..b497a25c30ac9298500cba17018841860eb240b8 100755
--- a/scripts/link-leanos.sh
+++ b/scripts/link-leanos.sh
@@ -309,7 +309,9 @@ if [ "$1" = "embed" ]; then
 	rm -f modules.image
 	${AR} rcs ${srctree}/modules.image \
 		$(tr '\n' ' ' < ${srctree}/modules.order) \
-		$(find dsp/xentium -name *.xen)
+		$(find dsp/xentium -name *.xen) \
+		"${CONFIG_EMBED_APPLICATION}"
+		
 
 	leanos_link "${kallsymso}" leanos "${embedflags}"
 	exit
diff --git a/tools/testing/hwtests/application/Makefile b/tools/testing/hwtests/application/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..96e88ca4e78aaaca8032f33f6616a7165bda9fdd
--- /dev/null
+++ b/tools/testing/hwtests/application/Makefile
@@ -0,0 +1,27 @@
+CC               = sparc-elf-gcc
+SOURCEDIR	 = ./
+INCLUDEDIR       = ./
+BUILDDIR         = ./
+PATH            +=
+CPPFLAGS        :=
+CFLAGS          := -r -mv8 -mhard-float -mfix-gr712rc -O2 -std=gnu89 -W -Wall \
+		   -Wextra -Werror -pedantic -Wshadow -Wuninitialized \
+		   -fdiagnostics-show-option -Wcast-qual -Wformat=2 \
+		   -nostartfiles -nostdlib
+LDFLAGS         :=
+SOURCES         := $(wildcard *.c) 
+OBJECTS         := $(patsubst %.c, $(BUILDDIR)/%.o, $(subst $(SOURCEDIR)/,, $(SOURCES)))
+TARGET          := executable_demo
+
+DEBUG?=1
+ifeq  "$(shell expr $(DEBUG) \> 1)" "1"
+	    CFLAGS += -DDEBUGLEVEL=$(DEBUG)
+else
+	    CFLAGS += -DDEBUGLEVEL=1
+endif
+
+
+all: $(SOURCES)
+	$(CC) $(CPPFLAGS) $(CFLAGS) $^ -o $(TARGET)
+
+
diff --git a/tools/testing/hwtests/application/README b/tools/testing/hwtests/application/README
new file mode 100644
index 0000000000000000000000000000000000000000..3e3fe3cdac1b43b70b999dcae01828d214d8706a
--- /dev/null
+++ b/tools/testing/hwtests/application/README
@@ -0,0 +1,26 @@
+
+Description:
+============
+
+This test configures and executes an embedded application demonstrator.
+
+Press Ctrl+C to quit the demonstration.
+
+Pass/Fail Criterea:
+===================
+
+	None
+
+Prerequisites:
+==============
+
+	* connected GR712 board
+	* grmon v2.x
+
+
+Notes:
+======
+
+The current .config of LeanOS will be overwritten and the image will
+be rebuilt.
+
diff --git a/tools/testing/hwtests/application/config b/tools/testing/hwtests/application/config
new file mode 100644
index 0000000000000000000000000000000000000000..7dbd6f625f610046fd1b8997b3e50e8bd792da0d
--- /dev/null
+++ b/tools/testing/hwtests/application/config
@@ -0,0 +1,72 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# LeanOS Configuration
+#
+
+#
+# SPARC Configuration
+#
+# CONFIG_LEON2 is not set
+CONFIG_LEON3=y
+# CONFIG_MMU is not set
+CONFIG_CPU_CLOCK_FREQ=80000000
+CONFIG_EXTRA_SPARC_PHYS_BANKS=0
+CONFIG_SPARC_CPU_REG_WINDOWS=8
+CONFIG_SPARC_TEXT_START=0x40000000
+CONFIG_SPARC_FP_START=0x40100000
+
+#
+# Memory Management Settings
+#
+CONFIG_SPARC_MM_BLOCK_ORDER_MAX=26
+CONFIG_SPARC_MM_BLOCK_ORDER_MIN=12
+CONFIG_SPARC_INIT_PAGE_MAP_MAX_ENTRIES=8
+CONFIG_SPARC_BOOTMEM_RESERVE_CHUNK_ORDER=20
+CONFIG_SPARC_BOOTMEM_REQUEST_NEW_ON_DEMAND=y
+CONFIG_SPARC_NESTED_IRQ=y
+
+#
+# General Setup
+#
+CONFIG_KALLSYMS=y
+CONFIG_CROSS_PLATFORM_TARGET=y
+CONFIG_CROSS_COMPILE="sparc-elf-"
+# CONFIG_TARGET_COMPILER_BOOT_CODE is not set
+CONFIG_ARCH_CUSTOM_BOOT_CODE=y
+CONFIG_MODULES=y
+CONFIG_EMBED_MODULES_IMAGE=y
+# CONFIG_BUILD_XEN_KERNELS is not set
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CC_OPTIMIZE_NONE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_KERNEL_PRINTK=y
+CONFIG_KERNEL_LEVEL=7
+# CONFIG_IRQ_STATS_COLLECT is not set
+# CONFIG_TASK_PREEMPTION_DISABLE is not set
+# CONFIG_SOC is not set
+
+#
+# Core Components
+#
+CONFIG_SYSCTL=y
+CONFIG_MM=y
+
+#
+# Memory Management Debug Options
+#
+# CONFIG_MM_DEBUG_DUMP is not set
+CONFIG_PAGE_MAP=y
+
+#
+# Page Map Options
+#
+# CONFIG_PAGE_MAP_CHECK_PAGE_ALIGNMENT is not set
+CONFIG_PAGE_MAP_MOVE_NODE_AVAIL_THRESH=1
+CONFIG_CHUNK=y
+CONFIG_AR=y
+# CONFIG_SAMPLES is not set
diff --git a/tools/testing/hwtests/application/executable_demo.c b/tools/testing/hwtests/application/executable_demo.c
new file mode 100644
index 0000000000000000000000000000000000000000..6ac004039967c5dde46472d2c9d7ae8fc2ec4bab
--- /dev/null
+++ b/tools/testing/hwtests/application/executable_demo.c
@@ -0,0 +1,79 @@
+/* This demonstrates a basic configuration for and "embedded application"
+ *
+ * Note that at this point, we do not distinguish between an application
+ * payload and a module, this will be changed in the future.
+ */
+
+
+#include "glue.h"
+
+
+
+
+/* some random function we use in our executable */
+
+static void print0r(int i)
+{
+	printk("print0r %d\n", i);
+}
+
+/* this is the equivalent of "main()" in our application
+ * (can actually be main I guess)
+ */
+
+static int iasw(void *data)
+{
+	int i;
+
+	(void) data;
+
+	/* print a little */
+	for (i = 0; i < 10; i++)
+		print0r(i);
+
+	/* then print a single "z" in a loop and "pause" until the function
+	 * is re-scheduled by issuing sched_yield()
+	 */
+
+	while (1) {
+		printk("z");
+		sched_yield();
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * This is our startup call, it will be executed once when the application is
+ * loaded. Here we create at thread in which our actual application code
+ * will run in.
+ */
+
+int init_iasw(void)
+{
+	struct task_struct *t;
+
+	t = kthread_create(iasw, (void *) 0, KTHREAD_CPU_AFFINITY_NONE, "IASW");
+	kthread_wake_up(t);
+
+	return 0;
+}
+
+
+/**
+ * this is our optional exit call, it will be called when the module/application
+ * is removed by the kernel
+ */
+
+int exit_iasw(void)
+{
+	printk("%s leaving\n", __func__);
+	/* kthread_destroy() */
+	return 0;
+}
+
+/* here we declare our init and exit functions */
+module_init(init_iasw)
+module_exit(exit_iasw)
diff --git a/tools/testing/hwtests/application/glue.h b/tools/testing/hwtests/application/glue.h
new file mode 100644
index 0000000000000000000000000000000000000000..8022d37ebc38cfee17eb5c0f1bc9adde5de9bdb8
--- /dev/null
+++ b/tools/testing/hwtests/application/glue.h
@@ -0,0 +1,29 @@
+#ifndef GLUE_H
+#define GLUE_H
+
+
+/*
+ * prototypes and declarations needed to build this demo
+ */
+
+#define module_init(initfunc)                                   \
+        int _module_init(void) __attribute__((alias(#initfunc)));
+
+#define module_exit(exitfunc)					\
+        int _module_exit(void) __attribute__((alias(#exitfunc)));
+
+#define KTHREAD_CPU_AFFINITY_NONE	(-1)
+
+int printk(const char *format, ...);
+
+struct task_struct *kthread_create(int (*thread_fn)(void *data),
+				   void *data, int cpu,
+				   const char *namefmt,
+				   ...);
+void kthread_wake_up(struct task_struct *task);
+
+void sched_yield(void);
+
+
+
+#endif /* GLUE_H */
diff --git a/tools/testing/hwtests/application/grmon_cmds b/tools/testing/hwtests/application/grmon_cmds
new file mode 100644
index 0000000000000000000000000000000000000000..05f292df204472001cf6c0004ecce992d33dede4
--- /dev/null
+++ b/tools/testing/hwtests/application/grmon_cmds
@@ -0,0 +1,3 @@
+load leanos
+run
+quit
diff --git a/tools/testing/hwtests/application/run_test.sh b/tools/testing/hwtests/application/run_test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9f4f0f44e5aba9b882ce61d27f94fbdc99dd6c32
--- /dev/null
+++ b/tools/testing/hwtests/application/run_test.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# grmon must be in path!
+
+
+#build application
+make || exit 1
+
+
+mydir=$PWD
+srcdir=../../../../
+
+cp config ${srcdir}/.config || exit 1
+
+echo -e "CONFIG_EMBED_APPLICATION=\"$PWD/executable_demo\"" >> ${srcdir}/.config
+
+cd ${srcdir} || exit 1
+
+make clean || exit 1
+
+make || exit 1
+
+grmon -ftdi -u -ftdifreq 0 -jtagcable 3 -nb -c $mydir/grmon_cmds