]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
objtool: Generalize elf_create_section()
authorJosh Poimboeuf <jpoimboe@kernel.org>
Wed, 17 Sep 2025 16:03:48 +0000 (09:03 -0700)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Tue, 14 Oct 2025 21:46:48 +0000 (14:46 -0700)
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>
tools/objtool/elf.c
tools/objtool/include/objtool/elf.h
tools/objtool/orc_gen.c

index d7703c848ce025ee11b502a1629093f1aa893643..7a7e63c7153f4131a1c6fc34ea53e944f1803eb7 100644 (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 (name && find_section_by_name(elf, name)) {
+               ERROR("section '%s' already exists", name);
+               return NULL;
+       }
+
+       sec = calloc(1, sizeof(*sec));
        if (!sec) {
-               ERROR_GLIBC("malloc");
+               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;
-       }
+       if (size) {
+               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_size = size;
+               sec->data->d_align = 1;
 
-       if (size) {
-               sec->data->d_buf = malloc(size);
+               sec->data->d_buf = calloc(1, size);
                if (!sec->data->d_buf) {
-                       ERROR_GLIBC("malloc");
+                       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;
-
-       /* 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;
+       sec->sh.sh_type = type;
+       sec->sh.sh_addralign = align;
+       sec->sh.sh_flags = flags;
+
+       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;
 
index c33b8fa0e3cecf25e8d1c80d27ad0018ca911f4f..badb10926d1e9f386a14de29a167d1939f516472 100644 (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,
index 6eff3d6a125c21c5fdc8df9c487bbb7dcef0b5f0..9d380abc2ed351209347c4b3684745bf0b6a8971 100644 (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;