From 8e982eabfacf9cce5bcc011ee2c23ca7ced4b05c Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Wed, 28 Oct 2015 10:09:07 -0500 Subject: cbfstool: merge consecutive elf sections in program segments Instead of creating a loadable segment for each section with SHF_ALLOC flag merge those sections into a single program segment. This makes more tidy readelf, but it also allows one to extract an rmodule into an ELF and turn it back into an rmodule. TEST=Extracted both regular stages and rmodule stages. Compared against original ELF files prior to cbfs insert. Change-Id: I0a600d2e9db5ee6c11278d8ad673caab1af6c759 Signed-off-by: Aaron Durbin Reviewed-on: http://review.coreboot.org/12220 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi Reviewed-by: Paul Menzel --- util/cbfstool/elfheaders.c | 95 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 17 deletions(-) (limited to 'util') diff --git a/util/cbfstool/elfheaders.c b/util/cbfstool/elfheaders.c index da11bfcb62..262137d580 100644 --- a/util/cbfstool/elfheaders.c +++ b/util/cbfstool/elfheaders.c @@ -841,6 +841,78 @@ phdr_write(struct elf_writer *ew, struct buffer *m, Elf64_Phdr *phdr) } +static int section_consecutive(struct elf_writer *ew, Elf64_Half secidx) +{ + Elf64_Half i; + struct elf_writer_section *prev_alloc = NULL; + + if (secidx == 0) + return 0; + + for (i = 0; i < secidx; i++) { + if (ew->sections[i].shdr.sh_flags & SHF_ALLOC) + prev_alloc = &ew->sections[i]; + } + + if (prev_alloc == NULL) + return 0; + + if (prev_alloc->shdr.sh_addr + prev_alloc->shdr.sh_size == + ew->sections[secidx].shdr.sh_addr) + return 1; + + return 0; +} + +static void write_phdrs(struct elf_writer *ew, struct buffer *phdrs) +{ + Elf64_Half i; + Elf64_Phdr phdr; + size_t num_written = 0; + + for (i = 0; i < ew->num_secs; i++) { + struct elf_writer_section *sec = &ew->sections[i]; + + if (!(sec->shdr.sh_flags & SHF_ALLOC)) + continue; + + if (!section_consecutive(ew, i)) { + /* Write out previously set phdr. */ + if (num_written != 0) { + phdr_write(ew, phdrs, &phdr); + num_written++; + } + 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; + } else { + /* Accumulate file size and memsize. The assumption + * is that each section is either NOBITS or full + * (sh_size == file size). This is standard in that + * an ELF section doesn't have a file size component. */ + 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_filesz += buffer_size(&sec->content); + phdr.p_memsz += sec->shdr.sh_size; + } + } + + /* Write out the last phdr. */ + if (num_written != ew->ehdr.e_phnum) + phdr_write(ew, phdrs, &phdr); +} + /* * Serialize the ELF file to the output buffer. Return < 0 on error, * 0 on success. @@ -866,8 +938,10 @@ int elf_writer_serialize(struct elf_writer *ew, struct buffer *out) 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++; + if (sec->shdr.sh_flags & SHF_ALLOC) { + if (!section_consecutive(ew, i)) + ew->ehdr.e_phnum++; + } program_size += buffer_size(&sec->content); @@ -924,7 +998,6 @@ int elf_writer_serialize(struct elf_writer *ew, struct buffer *out) * 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. */ @@ -944,21 +1017,9 @@ int elf_writer_serialize(struct elf_writer *ew, struct buffer *out) 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); } + write_phdrs(ew, &phdrs); + return 0; } -- cgit v1.2.3