objtool: Generalize elf_create_section()

In preparation for the objtool klp diff subcommand, broaden the
elf_create_section() interface to give callers more control and reduce
duplication of some subtle setup logic.

While at it, make elf_create_rela_section() global so sections can be
created by the upcoming klp diff code.

Acked-by: Petr Mladek <pmladek@suse.com>
Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
Josh Poimboeuf 2025-09-17 09:03:48 -07:00
parent dd2c29aafd
commit 243e963853
3 changed files with 77 additions and 54 deletions

View File

@ -1138,51 +1138,53 @@ static int elf_add_string(struct elf *elf, struct section *strtab, const char *s
}
struct section *elf_create_section(struct elf *elf, const char *name,
size_t entsize, unsigned int nr)
size_t size, size_t entsize,
unsigned int type, unsigned int align,
unsigned int flags)
{
struct section *sec, *shstrtab;
size_t size = entsize * nr;
Elf_Scn *s;
sec = malloc(sizeof(*sec));
if (!sec) {
ERROR_GLIBC("malloc");
if (name && find_section_by_name(elf, name)) {
ERROR("section '%s' already exists", name);
return NULL;
}
sec = calloc(1, sizeof(*sec));
if (!sec) {
ERROR_GLIBC("calloc");
return NULL;
}
memset(sec, 0, sizeof(*sec));
INIT_LIST_HEAD(&sec->symbol_list);
/* don't actually create the section, just the data structures */
if (type == SHT_NULL)
goto add;
s = elf_newscn(elf->elf);
if (!s) {
ERROR_ELF("elf_newscn");
return NULL;
}
sec->name = strdup(name);
if (!sec->name) {
ERROR_GLIBC("strdup");
return NULL;
}
sec->idx = elf_ndxscn(s);
sec->data = elf_newdata(s);
if (!sec->data) {
ERROR_ELF("elf_newdata");
return NULL;
}
sec->data->d_size = size;
sec->data->d_align = 1;
if (size) {
sec->data->d_buf = malloc(size);
if (!sec->data->d_buf) {
ERROR_GLIBC("malloc");
sec->data = elf_newdata(s);
if (!sec->data) {
ERROR_ELF("elf_newdata");
return NULL;
}
sec->data->d_size = size;
sec->data->d_align = 1;
sec->data->d_buf = calloc(1, size);
if (!sec->data->d_buf) {
ERROR_GLIBC("calloc");
return NULL;
}
memset(sec->data->d_buf, 0, size);
}
if (!gelf_getshdr(s, &sec->sh)) {
@ -1192,34 +1194,44 @@ struct section *elf_create_section(struct elf *elf, const char *name,
sec->sh.sh_size = size;
sec->sh.sh_entsize = entsize;
sec->sh.sh_type = SHT_PROGBITS;
sec->sh.sh_addralign = 1;
sec->sh.sh_flags = SHF_ALLOC;
sec->sh.sh_type = type;
sec->sh.sh_addralign = align;
sec->sh.sh_flags = flags;
/* Add section name to .shstrtab (or .strtab for Clang) */
shstrtab = find_section_by_name(elf, ".shstrtab");
if (!shstrtab)
shstrtab = find_section_by_name(elf, ".strtab");
if (!shstrtab) {
ERROR("can't find .shstrtab or .strtab section");
return NULL;
if (name) {
sec->name = strdup(name);
if (!sec->name) {
ERROR("strdup");
return NULL;
}
/* Add section name to .shstrtab (or .strtab for Clang) */
shstrtab = find_section_by_name(elf, ".shstrtab");
if (!shstrtab) {
shstrtab = find_section_by_name(elf, ".strtab");
if (!shstrtab) {
ERROR("can't find .shstrtab or .strtab");
return NULL;
}
}
sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
if (sec->sh.sh_name == -1)
return NULL;
elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));
}
sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
if (sec->sh.sh_name == -1)
return NULL;
add:
list_add_tail(&sec->list, &elf->sections);
elf_hash_add(section, &sec->hash, sec->idx);
elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));
mark_sec_changed(elf, sec, true);
return sec;
}
static struct section *elf_create_rela_section(struct elf *elf,
struct section *sec,
unsigned int reloc_nr)
struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
unsigned int reloc_nr)
{
struct section *rsec;
char *rsec_name;
@ -1232,22 +1244,23 @@ static struct section *elf_create_rela_section(struct elf *elf,
strcpy(rsec_name, ".rela");
strcat(rsec_name, sec->name);
rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
rsec = elf_create_section(elf, rsec_name, reloc_nr * elf_rela_size(elf),
elf_rela_size(elf), SHT_RELA, elf_addr_size(elf),
SHF_INFO_LINK);
free(rsec_name);
if (!rsec)
return NULL;
rsec->data->d_type = ELF_T_RELA;
rsec->sh.sh_type = SHT_RELA;
rsec->sh.sh_addralign = elf_addr_size(elf);
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
rsec->sh.sh_info = sec->idx;
rsec->sh.sh_flags = SHF_INFO_LINK;
rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
return NULL;
if (reloc_nr) {
rsec->data->d_type = ELF_T_RELA;
rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
if (!rsec->relocs) {
ERROR_GLIBC("calloc");
return NULL;
}
}
sec->rsec = rsec;
@ -1262,7 +1275,8 @@ struct section *elf_create_section_pair(struct elf *elf, const char *name,
{
struct section *sec;
sec = elf_create_section(elf, name, entsize, nr);
sec = elf_create_section(elf, name, nr * entsize, entsize,
SHT_PROGBITS, 1, SHF_ALLOC);
if (!sec)
return NULL;

View File

@ -117,11 +117,16 @@ struct elf {
struct elf *elf_open_read(const char *name, int flags);
struct section *elf_create_section(struct elf *elf, const char *name,
size_t entsize, unsigned int nr);
size_t size, size_t entsize,
unsigned int type, unsigned int align,
unsigned int flags);
struct section *elf_create_section_pair(struct elf *elf, const char *name,
size_t entsize, unsigned int nr,
unsigned int reloc_nr);
struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
unsigned int reloc_nr);
struct symbol *elf_create_symbol(struct elf *elf, const char *name,
struct section *sec, unsigned int bind,
unsigned int type, unsigned long offset,

View File

@ -127,7 +127,11 @@ int orc_create(struct objtool_file *file)
return -1;
}
orc_sec = elf_create_section(file->elf, ".orc_unwind",
sizeof(struct orc_entry), nr);
nr * sizeof(struct orc_entry),
sizeof(struct orc_entry),
SHT_PROGBITS,
1,
SHF_ALLOC);
if (!orc_sec)
return -1;