cbfstool: Make add-stage support multiple ignore sections

For x86 eXecute-In-Place (XIP) .data section support, cbfstool need to
to skip relocation of the .data section symbols in addition to
.car.data section symbols.

To support this requirement, this patch makes the `-S` option take a
multiple section names separated by commas.

TEST=With `-S ".car.data .data"`, XIP pre-memory stages with
     a `.data` section do not have any of the `.car.data` or `.data`
     section symbols relocated.

Change-Id: Icf09ee5a318e37c5da94bba6c0a0f39485963d3a
Signed-off-by: Jeremy Compostella <jeremy.compostella@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/77560
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Jeremy Compostella 2023-08-30 10:25:33 -07:00 committed by Julius Werner
parent 8bbadded83
commit c9cae530e5
2 changed files with 77 additions and 52 deletions

View File

@ -10,47 +10,66 @@
#include "cbfs.h"
#include "rmodule.h"
/* Checks if program segment contains the ignored section */
static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr *shdr)
/* Checks if program segment contains the ignored sections */
static int is_phdr_ignored(Elf64_Phdr *phdr, Elf64_Shdr **shdrs)
{
/* If no ignored section, return false. */
if (shdr == NULL)
if (shdrs == NULL)
return 0;
Elf64_Addr sh_start = shdr->sh_addr;
Elf64_Addr sh_end = shdr->sh_addr + shdr->sh_size;
Elf64_Addr ph_start = phdr->p_vaddr;
Elf64_Addr ph_end = phdr->p_vaddr + phdr->p_memsz;
while (*shdrs) {
Elf64_Addr sh_start = (*shdrs)->sh_addr;
Elf64_Addr sh_end = (*shdrs)->sh_addr + (*shdrs)->sh_size;
Elf64_Addr ph_start = phdr->p_vaddr;
Elf64_Addr ph_end = phdr->p_vaddr + phdr->p_memsz;
/* Return true only if section occupies whole of segment. */
if ((sh_start == ph_start) && (sh_end == ph_end)) {
DEBUG("Ignoring program segment at 0x%" PRIx64 "\n", ph_start);
return 1;
}
/* Return true only if section occupies whole of segment. */
if ((sh_start == ph_start) && (sh_end == ph_end)) {
DEBUG("Ignoring program segment at 0x%" PRIx64 "\n", ph_start);
return 1;
}
/* If shdr intersects phdr at all, its a conflict */
if (((sh_start >= ph_start) && (sh_start <= ph_end)) ||
((sh_end >= ph_start) && (sh_end <= ph_end))) {
ERROR("Conflicting sections in segment\n");
exit(1);
/* If shdr intersects phdr at all, its a conflict */
if (((sh_start >= ph_start) && (sh_start <= ph_end)) ||
((sh_end >= ph_start) && (sh_end <= ph_end))) {
ERROR("Conflicting sections in segment\n");
exit(1);
}
shdrs++;
}
/* Program header doesn't need to be ignored. */
return 0;
}
/* Find section header based on ignored section name */
static Elf64_Shdr *find_ignored_section_header(struct parsed_elf *pelf,
const char *ignore_section)
/* Sections to be ignored are comma separated */
static bool is_ignored_sections(const char *section_name,
const char *ignore_sections)
{
const char *cur, *comma;
for (cur = ignore_sections; (comma = strchr(cur, ',')); cur = comma + 1)
if (!strncmp(cur, section_name, comma - cur))
return true;
return !strcmp(cur, section_name);
}
/* Find section headers based on ignored section names.
* Returns a NULL-terminated list of section headers.
*/
static Elf64_Shdr **find_ignored_sections_header(struct parsed_elf *pelf,
const char *ignore_sections)
{
int i;
const char *shstrtab;
Elf64_Shdr **headers = NULL;
size_t size = 1;
/* No section needs to be ignored */
if (ignore_section == NULL)
if (ignore_sections == NULL)
return NULL;
DEBUG("Section to be ignored: %s\n", ignore_section);
DEBUG("Sections to be ignored: %s\n", ignore_sections);
/* Get pointer to string table */
shstrtab = buffer_get(pelf->strtabs[pelf->ehdr.e_shstrndx]);
@ -62,13 +81,20 @@ static Elf64_Shdr *find_ignored_section_header(struct parsed_elf *pelf,
shdr = &pelf->shdr[i];
section_name = &shstrtab[shdr->sh_name];
/* If section name matches ignored string, return shdr */
if (strcmp(section_name, ignore_section) == 0)
return shdr;
/* If section name matches ignored string, add to list */
if (is_ignored_sections(section_name, ignore_sections)) {
headers = realloc(headers, sizeof(*headers) * ++size);
if (!headers) {
ERROR("Memory allocation failed\n");
exit(1);
}
headers[size - 2] = shdr;
}
}
/* No section matches ignore string */
return NULL;
if (headers)
headers[size - 1] = NULL;
return headers;
}
static int fill_cbfs_stageheader(struct cbfs_file_attr_stageheader *stageheader,
@ -98,7 +124,7 @@ int parse_elf_to_stage(const struct buffer *input, struct buffer *output,
struct parsed_elf pelf;
Elf64_Phdr *phdr;
Elf64_Ehdr *ehdr;
Elf64_Shdr *shdr_ignored;
Elf64_Shdr **shdrs_ignored;
Elf64_Addr virt_to_phys;
int ret = -1;
@ -116,17 +142,17 @@ int parse_elf_to_stage(const struct buffer *input, struct buffer *output,
ehdr = &pelf.ehdr;
phdr = &pelf.phdr[0];
/* Find the section header corresponding to ignored-section */
shdr_ignored = find_ignored_section_header(&pelf, ignore_section);
/* Find the section headers corresponding to ignored-sections */
shdrs_ignored = find_ignored_sections_header(&pelf, ignore_section);
if (ignore_section && (shdr_ignored == NULL))
WARN("Ignore section not found\n");
if (ignore_section && (shdrs_ignored == NULL))
WARN("Ignore section(s) not found\n");
headers = ehdr->e_phnum;
/* Ignore the program header containing ignored section */
for (i = 0; i < headers; i++) {
if (is_phdr_ignored(&phdr[i], shdr_ignored))
if (is_phdr_ignored(&phdr[i], shdrs_ignored))
phdr[i].p_type = PT_NULL;
}
@ -217,8 +243,7 @@ err:
struct xip_context {
struct rmod_context rmodctx;
size_t ignored_section_idx;
Elf64_Shdr *ignored_section;
Elf64_Shdr **ignored_sections;
};
static int rmod_filter(struct reloc_filter *f, const Elf64_Rela *r)
@ -228,12 +253,13 @@ static int rmod_filter(struct reloc_filter *f, const Elf64_Rela *r)
struct parsed_elf *pelf;
Elf64_Sym *sym;
struct xip_context *xipctx;
Elf64_Shdr **sections;
xipctx = f->context;
pelf = &xipctx->rmodctx.pelf;
/* Allow everything through if there isn't an ignored section. */
if (xipctx->ignored_section == NULL)
if (xipctx->ignored_sections == NULL)
return 1;
reloc_type = ELF64_R_TYPE(r->r_info);
@ -241,8 +267,11 @@ static int rmod_filter(struct reloc_filter *f, const Elf64_Rela *r)
sym = &pelf->syms[symbol_index];
/* Nothing to filter. Relocation is not being applied to the
* ignored section. */
if (sym->st_shndx != xipctx->ignored_section_idx)
* ignored sections. */
for (sections = xipctx->ignored_sections; *sections; sections++)
if (sym->st_shndx == *sections - pelf->shdr)
break;
if (!*sections)
return 1;
/* If there is any relocation to the ignored section that isn't
@ -255,12 +284,12 @@ static int rmod_filter(struct reloc_filter *f, const Elf64_Rela *r)
return -1;
}
/* Relocation referencing ignored section. Don't emit it. */
/* Relocation referencing ignored sections. Don't emit it. */
return 0;
}
int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output,
uint32_t location, const char *ignore_section,
uint32_t location, const char *ignore_sections,
struct cbfs_file_attr_stageheader *stageheader)
{
struct xip_context xipctx;
@ -273,7 +302,6 @@ int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output,
Elf64_Xword i;
int ret = -1;
xipctx.ignored_section_idx = 0;
rmodctx = &xipctx.rmodctx;
pelf = &rmodctx->pelf;
@ -287,12 +315,8 @@ int parse_elf_to_xip_stage(const struct buffer *input, struct buffer *output,
goto out;
}
xipctx.ignored_section =
find_ignored_section_header(pelf, ignore_section);
if (xipctx.ignored_section != NULL)
xipctx.ignored_section_idx =
xipctx.ignored_section - pelf->shdr;
xipctx.ignored_sections =
find_ignored_sections_header(pelf, ignore_sections);
filter.filter = rmod_filter;
filter.context = &xipctx;

View File

@ -46,7 +46,7 @@ static struct param {
const char *region_name;
const char *source_region;
const char *bootblock;
const char *ignore_section;
const char *ignore_sections;
const char *ucode_region;
uint64_t u64val;
uint32_t type;
@ -1179,9 +1179,9 @@ static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset,
uint32_t host_space_address = convert_addr_space(param.image_region, *offset);
assert(IS_HOST_SPACE_ADDRESS(host_space_address));
ret = parse_elf_to_xip_stage(buffer, &output, host_space_address,
param.ignore_section, stageheader);
param.ignore_sections, stageheader);
} else {
ret = parse_elf_to_stage(buffer, &output, param.ignore_section,
ret = parse_elf_to_stage(buffer, &output, param.ignore_sections,
stageheader);
}
if (ret != 0)
@ -1968,7 +1968,8 @@ static void usage(char *name)
" (linux specific: [-C cmdline] [-I initrd]) "
"Add a payload to the ROM\n"
" add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
" [-c compression] [-b base] [-S section-to-ignore] \\\n"
" [-c compression] [-b base] \\\n"
" [-S comma-separated-section(s)-to-ignore] \\\n"
" [-a alignment] [-Q|--pow2page] \\\n"
" [-y|--xip] [--ibb] \\\n"
" [--ext-win-base win-base --ext-win-size win-size] "
@ -2271,7 +2272,7 @@ int main(int argc, char **argv)
param.cmdline = optarg;
break;
case 'S':
param.ignore_section = optarg;
param.ignore_sections = optarg;
break;
case 'y':
param.stage_xip = true;