[coreboot-gerrit] New patch to review for coreboot: 92831c2 cbfstool: add ELF writing support

Aaron Durbin (adurbin@google.com) gerrit at coreboot.org
Tue Mar 11 18:11:49 CET 2014


Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5377

-gerrit

commit 92831c262b08a9c379559a80ac9960f7364c1646
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Tue Mar 11 11:48:56 2014 -0500

    cbfstool: add ELF writing support
    
    In order to generate rmodules in the format of ELF files
    there needs to be support for writing out ELF files. The
    ELF writer is fairly simple. It accpets sections that can
    be associated with an optional buffer (file data). For each
    section flagged with SHF_ALLOC a PT_LOAD segment is generated.
    There isn't smart merging of the sections into a single PT_LOAD
    segment.
    
    Change-Id: I4d1a11f2e65be2369fb3f8bff350cbb28e14c89d
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 util/cbfstool/elfheaders.c | 319 +++++++++++++++++++++++++++++++++++++++++++++
 util/cbfstool/elfparsing.h |  31 +++++
 2 files changed, 350 insertions(+)

diff --git a/util/cbfstool/elfheaders.c b/util/cbfstool/elfheaders.c
index 6818d72..8ba5f3f 100644
--- a/util/cbfstool/elfheaders.c
+++ b/util/cbfstool/elfheaders.c
@@ -630,3 +630,322 @@ elf_headers(const struct buffer *pinput,
 
 	return 0;
 }
+
+/* ELF Writing  Support
+ *
+ * The ELF file is written according to the following layout:
+ * +------------------+
+ * |    ELF Header    |
+ * +------------------+
+ * | Section  Headers |
+ * +------------------+
+ * | Program  Headers |
+ * +------------------+
+ * |   String table   |
+ * +------------------+ <- 4KiB Aligned
+ * |     Code/Data    |
+ * +------------------+
+ */
+
+/* Arbitray maximum number of sections. */
+#define MAX_SECTIONS 16
+struct elf_writer_section {
+	Elf64_Shdr shdr;
+	struct buffer content;
+	const char *name;
+};
+
+struct elf_writer
+{
+	Elf64_Ehdr ehdr;
+	struct xdr *xdr;
+	size_t num_secs;
+	struct elf_writer_section sections[MAX_SECTIONS];
+	Elf64_Phdr *phdrs;
+	struct elf_writer_section *shstrtab;
+	int bit64;
+};
+
+struct elf_writer *elf_writer_init(const Elf64_Ehdr *ehdr)
+{
+	struct elf_writer *ew;
+	Elf64_Shdr shdr;
+	struct buffer empty_buffer;
+
+	if (!iself(ehdr))
+		return NULL;
+
+	ew = calloc(1, sizeof(*ew));
+
+	memcpy(&ew->ehdr, ehdr, sizeof(ew->ehdr));
+
+	ew->bit64 = ew->ehdr.e_ident[EI_CLASS] == ELFCLASS64;
+
+	/* Set the endinan ops. */
+	if (ew->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+		ew->xdr = &xdr_be;
+	else
+		ew->xdr = &xdr_le;
+
+	/* Reset count and offsets */
+	ew->ehdr.e_phoff = 0;
+	ew->ehdr.e_shoff = 0;
+	ew->ehdr.e_shnum = 0;
+	ew->ehdr.e_phnum = 0;
+
+	memset(&empty_buffer, 0, sizeof(empty_buffer));
+	memset(&shdr, 0, sizeof(shdr));
+
+	/* Add SHT_NULL section header. */
+	shdr.sh_type = SHT_NULL;
+	elf_writer_add_section(ew, &shdr, &empty_buffer, NULL);
+
+	/* Add section header string table and maintain reference to it.  */
+	shdr.sh_type = SHT_STRTAB;
+	elf_writer_add_section(ew, &shdr, &empty_buffer, ".shstrtab");
+	ew->ehdr.e_shstrndx = ew->num_secs - 1;
+	ew->shstrtab = &ew->sections[ew->ehdr.e_shstrndx];
+
+	return ew;
+}
+
+/*
+ * Clean up any internal state represented by ew. Aftewards the elf_writer
+ * is invalid.
+ */
+void elf_writer_destroy(struct elf_writer *ew)
+{
+	if (ew->phdrs != NULL)
+		free(ew->phdrs);
+	free(ew);
+}
+
+/*
+ * Add a section to the ELF file. Section type, flags, and memsize are
+ * maintained from the passed in Elf64_Shdr. The buffer represents the
+ * content of the section while the name is the name of section itself.
+ * Returns < 0 on error, 0 on success.
+ */
+int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr,
+                           struct buffer *contents, const char *name)
+{
+	struct elf_writer_section *newsh;
+
+	if (ew->num_secs == MAX_SECTIONS)
+		return -1;
+
+	newsh = &ew->sections[ew->num_secs];
+	ew->num_secs++;
+
+	memcpy(&newsh->shdr, shdr, sizeof(newsh->shdr));
+	newsh->shdr.sh_offset = 0;
+
+	newsh->name = name;
+	if (contents != NULL)
+		buffer_clone(&newsh->content, contents);
+
+	return 0;
+}
+
+static void ehdr_write(struct elf_writer *ew, struct buffer *m)
+{
+	int i;
+
+	for (i = 0; i < EI_NIDENT; i++)
+		ew->xdr->put8(m, ew->ehdr.e_ident[i]);
+	ew->xdr->put16(m, ew->ehdr.e_type);
+	ew->xdr->put16(m, ew->ehdr.e_machine);
+	ew->xdr->put32(m, ew->ehdr.e_version);
+	if (ew->bit64) {
+		ew->xdr->put64(m, ew->ehdr.e_entry);
+		ew->xdr->put64(m, ew->ehdr.e_phoff);
+		ew->xdr->put64(m, ew->ehdr.e_shoff);
+	} else {
+		ew->xdr->put32(m, ew->ehdr.e_entry);
+		ew->xdr->put32(m, ew->ehdr.e_phoff);
+		ew->xdr->put32(m, ew->ehdr.e_shoff);
+	}
+	ew->xdr->put32(m, ew->ehdr.e_flags);
+	ew->xdr->put16(m, ew->ehdr.e_ehsize);
+	ew->xdr->put16(m, ew->ehdr.e_phentsize);
+	ew->xdr->put16(m, ew->ehdr.e_phnum);
+	ew->xdr->put16(m, ew->ehdr.e_shentsize);
+	ew->xdr->put16(m, ew->ehdr.e_shnum);
+	ew->xdr->put16(m, ew->ehdr.e_shstrndx);
+}
+
+static void shdr_write(struct elf_writer *ew, size_t n, struct buffer *m)
+{
+	struct xdr *xdr = ew->xdr;
+	int bit64 = ew->bit64;
+	struct elf_writer_section *sec = &ew->sections[n];
+	Elf64_Shdr *shdr = &sec->shdr;
+
+	xdr->put32(m, shdr->sh_name);
+	xdr->put32(m, shdr->sh_type);
+	xdr->put32(m, shdr->sh_flags);
+	if (bit64) {
+		xdr->put64(m, shdr->sh_addr);
+		xdr->put64(m, shdr->sh_offset);
+		xdr->put64(m, shdr->sh_size);
+		xdr->put32(m, shdr->sh_link);
+		xdr->put32(m, shdr->sh_info);
+		xdr->put64(m, shdr->sh_addralign);
+		xdr->put64(m, shdr->sh_entsize);
+	} else {
+		xdr->put32(m, shdr->sh_addr);
+		xdr->put32(m, shdr->sh_offset);
+		xdr->put32(m, shdr->sh_size);
+		xdr->put32(m, shdr->sh_link);
+		xdr->put32(m, shdr->sh_info);
+		xdr->put32(m, shdr->sh_addralign);
+		xdr->put32(m, shdr->sh_entsize);
+	}
+}
+
+static void
+phdr_write(struct elf_writer *ew, struct buffer *m, Elf64_Phdr *phdr)
+{
+	if (ew->bit64) {
+		ew->xdr->put32(m, phdr->p_type);
+		ew->xdr->put32(m, phdr->p_flags);
+		ew->xdr->put64(m, phdr->p_offset);
+		ew->xdr->put64(m, phdr->p_vaddr);
+		ew->xdr->put64(m, phdr->p_paddr);
+		ew->xdr->put64(m, phdr->p_filesz);
+		ew->xdr->put64(m, phdr->p_memsz);
+		ew->xdr->put64(m, phdr->p_align);
+	} else {
+		ew->xdr->put32(m, phdr->p_type);
+		ew->xdr->put32(m, phdr->p_offset);
+		ew->xdr->put32(m, phdr->p_vaddr);
+		ew->xdr->put32(m, phdr->p_paddr);
+		ew->xdr->put32(m, phdr->p_filesz);
+		ew->xdr->put32(m, phdr->p_memsz);
+		ew->xdr->put32(m, phdr->p_flags);
+		ew->xdr->put32(m, phdr->p_align);
+	}
+
+}
+
+/*
+ * Serialize the ELF file to the output buffer. Return < 0 on error,
+ * 0 on success.
+ */
+int elf_writer_serialize(struct elf_writer *ew, struct buffer *out)
+{
+	Elf64_Half i;
+	Elf64_Xword metadata_size;
+	Elf64_Xword program_size;
+	Elf64_Off shstroffset;
+	size_t shstrlen;
+	struct buffer metadata;
+	struct buffer phdrs;
+	struct buffer data;
+	struct buffer *strtab;
+
+	INFO("Writing %zu sections.\n", ew->num_secs);
+
+	/* Determine size of sections to be written. */
+	program_size = 0;
+	/* Start with 1 byte for first byte of section header string table. */
+	shstrlen = 1;
+	for (i = 0; i < ew->num_secs; i++) {
+		struct elf_writer_section *sec = &ew->sections[i];
+
+		if (sec->shdr.sh_flags & SHF_ALLOC)
+			ew->ehdr.e_phnum++;
+
+		program_size += buffer_size(&sec->content);
+
+		/* Keep track of the length sections' names. */
+		if (sec->name != NULL) {
+			sec->shdr.sh_name = shstrlen;
+			shstrlen += strlen(sec->name) + 1;
+		}
+	}
+	ew->ehdr.e_shnum = ew->num_secs;
+	metadata_size = 0;
+	metadata_size += ew->ehdr.e_ehsize;
+	metadata_size += ew->ehdr.e_shnum * ew->ehdr.e_shentsize;
+	metadata_size += ew->ehdr.e_phnum * ew->ehdr.e_phentsize;
+	shstroffset = metadata_size;
+	/* Align up section header string size and metadata size to 4KiB */
+	metadata_size = ALIGN(metadata_size + shstrlen, 4096);
+
+	if (buffer_create(out, metadata_size + program_size, "elfout")) {
+		ERROR("Could not create output buffer for ELF.\n");
+		return -1;
+	}
+
+	INFO("Created %zu output buffer for ELF file.\n", buffer_size(out));
+
+	/*
+	 * Write out ELF header. Section headers come right after ELF header
+	 * followed by the program headers. Buffers need to be created first
+	 * to do the writing.
+	 */
+	ew->ehdr.e_shoff = ew->ehdr.e_ehsize;
+	ew->ehdr.e_phoff = ew->ehdr.e_shoff +
+	                   ew->ehdr.e_shnum * ew->ehdr.e_shentsize;
+
+	buffer_splice(&metadata, out, 0, metadata_size);
+	buffer_splice(&phdrs, out, ew->ehdr.e_phoff,
+	              ew->ehdr.e_phnum * ew->ehdr.e_phentsize);
+	buffer_splice(&data, out, metadata_size, program_size);
+	/* Set up the section header string table contents. */
+	strtab = &ew->shstrtab->content;
+	buffer_splice(strtab, out, shstroffset, shstrlen);
+	ew->shstrtab->shdr.sh_size = shstrlen;
+
+	/* Reset current locations. */
+	buffer_set_size(&metadata, 0);
+	buffer_set_size(&data, 0);
+	buffer_set_size(&phdrs, 0);
+	buffer_set_size(strtab, 0);
+
+	/* ELF Header */
+	ehdr_write(ew, &metadata);
+
+	/* Write out section headers, section strings, section content, and
+	 * program headers. */
+	ew->xdr->put8(strtab, 0);
+	for (i = 0; i < ew->num_secs; i++) {
+		Elf64_Phdr phdr;
+		struct elf_writer_section *sec = &ew->sections[i];
+
+		/* Update section offsets. Be sure to not update SHT_NULL. */
+		if (sec == ew->shstrtab)
+			sec->shdr.sh_offset = shstroffset;
+		else if (i != 0)
+			sec->shdr.sh_offset = buffer_size(&data) +
+			                      metadata_size;
+		shdr_write(ew, i, &metadata);
+
+		/* Add section name to string table. */
+		if (sec->name != NULL)
+			bputs(strtab, sec->name, strlen(sec->name) + 1);
+
+		if (!(sec->shdr.sh_flags & SHF_ALLOC))
+			continue;
+
+		bputs(&data, buffer_get(&sec->content),
+		      buffer_size(&sec->content));
+
+		phdr.p_type = PT_LOAD;
+		phdr.p_offset = sec->shdr.sh_offset;
+		phdr.p_vaddr = sec->shdr.sh_addr;
+		phdr.p_paddr = sec->shdr.sh_addr;
+		phdr.p_filesz = buffer_size(&sec->content);
+		phdr.p_memsz = sec->shdr.sh_size;
+		phdr.p_flags = 0;
+		if (sec->shdr.sh_flags & SHF_EXECINSTR)
+			phdr.p_flags |= PF_X | PF_R;
+		if (sec->shdr.sh_flags & SHF_WRITE)
+			phdr.p_flags |= PF_W;
+		phdr.p_align = sec->shdr.sh_addralign;
+		phdr_write(ew, &phdrs, &phdr);
+	}
+
+	return 0;
+}
diff --git a/util/cbfstool/elfparsing.h b/util/cbfstool/elfparsing.h
index 113301a..048d31a 100644
--- a/util/cbfstool/elfparsing.h
+++ b/util/cbfstool/elfparsing.h
@@ -74,4 +74,35 @@ elf_headers(const struct buffer *pinput,
 	    Elf64_Phdr **pphdr,
 	    Elf64_Shdr **pshdr);
 
+/* ELF writing support. */
+struct elf_writer;
+
+/*
+ * Initialize a new ELF writer. Deafult machine type, endianness, etc is
+ * copied from the passed in Elf64_Ehdr. Returns NULL on failure, valid
+ * pointer on success.
+ */
+struct elf_writer *elf_writer_init(const Elf64_Ehdr *ehdr);
+
+/*
+ * Clean up any internal state represented by ew. Aftewards the elf_writer
+ * is invalid.
+ */
+void elf_writer_destroy(struct elf_writer *ew);
+
+/*
+ * Add a section to the ELF file. Section type, flags, and memsize are
+ * maintained from the passed in Elf64_Shdr. The buffer represents the
+ * content of the section while the name is the name of section itself.
+ * Returns < 0 on error, 0 on success.
+ */
+int elf_writer_add_section(struct elf_writer *ew, const Elf64_Shdr *shdr,
+                           struct buffer *contents, const char *name);
+
+/*
+ * Serialize the ELF file to the output buffer. Return < 0 on error,
+ * 0 on success.
+ */
+int elf_writer_serialize(struct elf_writer *ew, struct buffer *out);
+
 #endif /* ELFPARSING_H */



More information about the coreboot-gerrit mailing list