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:
parent
8bbadded83
commit
c9cae530e5
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue