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 <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/12220
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
This commit is contained in:
Aaron Durbin 2015-10-28 10:09:07 -05:00
parent 5a1e85c405
commit 8e982eabfa
1 changed files with 78 additions and 17 deletions

View File

@ -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;
}