[U-Boot] [PATCH] envcrc: extract default environment from target ELF files

Mike Frysinger vapier at gentoo.org
Tue Jun 16 11:05:08 CEST 2009


Rather than rely on dirty hacks to compile the environment on the host and
extract the CRC from that, have envcrc extract the environment straight
from the ELF object that will be linked into u-boot itself.  This makes
the envcrc code a bit more complicated, but it simplifies the build
process and host requirements because we don't have to try and recreate
the environment that the target will be seeing on the host.  This avoids
some issues that crop up from time to time where the preprocessor defines
on the host don't expand in the same way as for the target -- in case the
target uses those defines to customize the environment, or the host
defines conflicts with some of the target values.

Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
 common/Makefile       |    4 +-
 common/env_embedded.c |   30 +---------
 tools/Makefile        |    3 +-
 tools/envcrc.c        |  156 ++++++++++++++++++++++++++++++++++++++++++-------

diff --git a/common/Makefile b/common/Makefile
index c8e5d26..02bc71b 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -173,9 +173,9 @@ all:	$(LIB) $(AOBJS)
 $(LIB): $(obj).depend $(OBJS)
 	$(AR) $(ARFLAGS) $@ $(OBJS)
 
-$(obj)env_embedded.o: $(src)env_embedded.c $(obj)../tools/envcrc
+$(obj)env_embedded.o: $(src)env_embedded.c $(obj)env_common.o $(obj)../tools/envcrc
 	$(CC) $(AFLAGS) -Wa,--no-warn \
-		-DENV_CRC=$(shell $(obj)../tools/envcrc) \
+		-DENV_CRC=$(shell $(obj)../tools/envcrc $(obj)env_common.o) \
 		-c -o $@ $(src)env_embedded.c
 
 $(obj)../tools/envcrc:
diff --git a/common/env_embedded.c b/common/env_embedded.c
index ae6cac4..60736c7 100644
--- a/common/env_embedded.c
+++ b/common/env_embedded.c
@@ -21,26 +21,10 @@
  * MA 02111-1307 USA
  */
 
-#ifndef __ASSEMBLY__
-#define	__ASSEMBLY__			/* Dirty trick to get only #defines	*/
-#endif
-#define	__ASM_STUB_PROCESSOR_H__	/* don't include asm/processor.		*/
 #include <config.h>
-#undef	__ASSEMBLY__
 #include <environment.h>
 
 /*
- * Handle HOSTS that have prepended
- * crap on symbol names, not TARGETS.
- */
-#if defined(__APPLE__)
-/* Leading underscore on symbols */
-#  define SYM_CHAR "_"
-#else /* No leading character on symbols */
-#  define SYM_CHAR
-#endif
-
-/*
  * Generate embedded environment table
  * inside U-Boot image, if needed.
  */
@@ -75,7 +59,7 @@
 #else
 # define GEN_SET_VALUE(name, value) asm (GEN_SYMNAME(name) " = " GEN_VALUE(value))
 #endif
-#define GEN_SYMNAME(str) SYM_CHAR #str
+#define GEN_SYMNAME(str) #str
 #define GEN_VALUE(str) #str
 #define GEN_ABS(name, value) \
 		asm (".globl " GEN_SYMNAME(name)); \
@@ -197,17 +181,7 @@ env_t redundand_environment __PPCENV__ = {
 #endif	/* CONFIG_ENV_ADDR_REDUND */
 
 /*
- * These will end up in the .text section
- * if the environment strings are embedded
- * in the image.  When this is used for
- * tools/envcrc, they are placed in the
- * .data/.sdata section.
- *
- */
-unsigned long env_size __PPCTEXT__ = sizeof(env_t);
-
-/*
- * Add in absolutes.
+ * Add in absolutes.  This symbol is only referenced from linker scripts.
  */
 GEN_ABS(env_offset, CONFIG_ENV_OFFSET);
 
diff --git a/tools/Makefile b/tools/Makefile
index 43c284c..982d65a 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -80,7 +80,6 @@ BIN_FILES-$(CONFIG_INCA_IP) += inca-swap-bytes$(SFX)
 BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
 
 # Source files which exist outside the tools directory
-EXT_OBJ_FILES-y += common/env_embedded.o
 EXT_OBJ_FILES-y += lib_generic/crc32.o
 EXT_OBJ_FILES-y += lib_generic/md5.o
 EXT_OBJ_FILES-y += lib_generic/sha1.o
@@ -156,7 +155,7 @@ MAKEDEPEND = makedepend
 
 all:	$(obj).depend $(BINS) $(LOGO-y) subdirs
 
-$(obj)envcrc$(SFX):	$(obj)envcrc.o $(obj)crc32.o $(obj)env_embedded.o $(obj)sha1.o
+$(obj)envcrc$(SFX):	$(obj)envcrc.o $(obj)crc32.o $(obj)sha1.o
 	$(CC) $(CFLAGS) -o $@ $^
 
 $(obj)ubsha1$(SFX):	$(obj)ubsha1.o $(obj)sha1.o $(obj)os_support.o
diff --git a/tools/envcrc.c b/tools/envcrc.c
index 5b0f7cd..87453e5 100644
--- a/tools/envcrc.c
+++ b/tools/envcrc.c
@@ -21,11 +21,15 @@
  * MA 02111-1307 USA
  */
 
+#include "compiler.h"
+#include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include "elf.h"
 
 #ifndef __ASSEMBLY__
 #define	__ASSEMBLY__			/* Dirty trick to get only #defines	*/
@@ -67,48 +71,156 @@
 
 #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
 
+unsigned char host_endian(void)
+{
+	struct {
+		union {
+			uint16_t sint;
+			unsigned char str[2];
+		} u;
+	} data;
+	data.u.sint = 0xBBAA;
+	return data.u.str[0] == 0xBB ? ELFDATA2MSB : ELFDATA2LSB;
+}
+bool swapit;
+#define EGET(val) ( \
+	!swapit ? (val) : \
+		sizeof(val) == 1 ? (val) : \
+		sizeof(val) == 2 ? uswap_16(val) : \
+		sizeof(val) == 4 ? uswap_32(val) : \
+		sizeof(val) == 8 ? uswap_64(val) : \
+		1 \
+)
 
 extern uint32_t crc32 (uint32_t, const unsigned char *, unsigned int);
 
-#ifdef	ENV_IS_EMBEDDED
-extern unsigned int env_size;
-extern unsigned char environment;
-#endif	/* ENV_IS_EMBEDDED */
+static bool elfread(FILE *fp, long offset, void *ptr, size_t size, size_t nmemb)
+{
+	if (fseek(fp, offset, SEEK_SET))
+		return false;
+	if (fread(ptr, size, nmemb, fp) != nmemb)
+		return false;
+	return true;
+}
+
+/* Avoid using elf.h since not all systems have it */
+unsigned char environment[CONFIG_ENV_SIZE];
+bool read_env_from_elf(const char *elf_file)
+{
+	const char env_symbol[] = "default_environment";
+	char buf[256];
+	FILE *fp;
+	bool ret = false;
+	int i;
+
+	Elf32_Ehdr ehdr;
+	Elf32_Shdr shdr, strtab, symtab;
+	Elf32_Sym sym;
+
+	fp = fopen(elf_file, "r");
+	if (!fp)
+		return false;
+
+	/* Make sure this is a valid ELF */
+	if (!elfread(fp, 0, &ehdr, sizeof(ehdr), 1))
+		goto done;
+	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG)) {
+		errno = EINVAL;
+		goto done;
+	}
+	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+		errno = EINVAL;
+		goto done;
+	}
+	swapit = host_endian() == ehdr.e_ident[EI_DATA] ? false : true;
+
+	/* Find the string & symbol table */
+	memset(&strtab, 0, sizeof(strtab)); /* shut gcc the hell up */
+	memset(&symtab, 0, sizeof(symtab)); /* shut gcc the hell up */
+	strtab.sh_type = SHT_NULL;
+	symtab.sh_type = SHT_NULL;
+	for (i = 0; i < EGET(ehdr.e_shnum); ++i) {
+		long off = EGET(ehdr.e_shoff) + i * EGET(ehdr.e_shentsize);
+		if (!elfread(fp, off, &shdr, sizeof(shdr), 1))
+			goto done;
+		if (EGET(shdr.sh_type) == SHT_STRTAB)
+			strtab = shdr;
+		else if (EGET(shdr.sh_type) == SHT_SYMTAB)
+			symtab = shdr;
+	}
+	if (strtab.sh_type == SHT_NULL || symtab.sh_type == SHT_NULL) {
+		errno = EINVAL;
+		goto done;
+	}
+
+	/* Find the environment symbol */
+	for (i = 0; i < EGET(symtab.sh_size) / EGET(symtab.sh_entsize); ++i) {
+		char *tbuf;
+		long off = EGET(symtab.sh_offset) + i * sizeof(sym);
+		if (!elfread(fp, off, &sym, sizeof(sym), 1))
+			goto done;
+		off = EGET(strtab.sh_offset) + EGET(sym.st_name);
+		tbuf = buf;
+		if (!elfread(fp, off, tbuf, 1, sizeof(env_symbol)))
+			goto done;
+		/* handle ABI prefixed symbols automatically */
+		if (tbuf[0] == '_') {
+			tbuf[sizeof(env_symbol)] = '\0';
+			++tbuf;
+		}
+		if (!strcmp(tbuf, env_symbol)) {
+			off = EGET(ehdr.e_shoff) + EGET(sym.st_shndx) * EGET(ehdr.e_shentsize);
+			if (!elfread(fp, off, &shdr, sizeof(shdr), 1))
+				goto done;
+			off = EGET(shdr.sh_offset) + EGET(sym.st_value);
+			if (!elfread(fp, off, environment + ENV_HEADER_SIZE, 1, EGET(sym.st_size)))
+				goto done;
+			ret = true;
+			break;
+		}
+	}
+
+ done:
+	fclose(fp);
+	return ret;
+}
 
 int main (int argc, char **argv)
 {
-#ifdef	ENV_IS_EMBEDDED
+#ifdef	ENV_IS_EMBEDDED
 	unsigned char pad = 0x00;
 	uint32_t crc;
-	unsigned char *envptr = &environment,
+	unsigned char *envptr = environment,
 		*dataptr = envptr + ENV_HEADER_SIZE;
 	unsigned int datasize = ENV_SIZE;
-	unsigned int eoe;
+	const char *env_file;
 
-	if (argv[1] && !strncmp(argv[1], "--binary", 8)) {
+	if (argc < 2) {
+		puts("Usage: envcrc <environment object> [--binary [le]]");
+		return 1;
+	}
+	env_file = argv[1];
+
+	if (argv[2] && !strncmp(argv[2], "--binary", 8)) {
 		int ipad = 0xff;
-		if (argv[1][8] == '=')
-			sscanf(argv[1] + 9, "%i", &ipad);
+		if (argv[2][8] == '=')
+			sscanf(argv[2] + 9, "%i", &ipad);
 		pad = ipad;
 	}
+	memset(dataptr, pad, datasize);
 
-	if (pad) {
-		/* find the end of env */
-		for (eoe = 0; eoe < datasize - 1; ++eoe)
-			if (!dataptr[eoe] && !dataptr[eoe+1]) {
-				eoe += 2;
-				break;
-			}
-		if (eoe < datasize - 1)
-			memset(dataptr + eoe, pad, datasize - eoe);
+	if (!read_env_from_elf(env_file)) {
+		fprintf(stderr, "unable to read environment from %s: %s\n",
+			env_file, strerror(errno));
+		return 1;
 	}
 
 	crc = crc32 (0, dataptr, datasize);
 
 	/* Check if verbose mode is activated passing a parameter to the program */
-	if (argc > 1) {
-		if (!strncmp(argv[1], "--binary", 8)) {
-			int le = (argc > 2 ? !strcmp(argv[2], "le") : 1);
+	if (argc > 2) {
+		if (!strncmp(argv[2], "--binary", 8)) {
+			int le = (argc > 3 ? !strcmp(argv[3], "le") : 1);
 			size_t i, start, end, step;
 			if (le) {
 				start = 0;
-- 
1.6.3.1



More information about the U-Boot mailing list