objtool: Add elf_create_data()

In preparation for the objtool klp diff subcommand, refactor
elf_add_string() by adding a new elf_add_data() helper which allows the
adding of arbitrary data to a section.

Make both interfaces global so they can be used 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:49 -07:00
parent 243e963853
commit 431dbabf2d
2 changed files with 54 additions and 22 deletions

View File

@ -18,10 +18,11 @@
#include <errno.h>
#include <linux/interval_tree_generic.h>
#include <objtool/builtin.h>
#include <objtool/elf.h>
#include <objtool/warn.h>
#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
static inline u32 str_hash(const char *str)
{
return jhash(str, strlen(str), 0);
@ -763,8 +764,6 @@ static int elf_update_symbol(struct elf *elf, struct section *symtab,
return 0;
}
static int elf_add_string(struct elf *elf, struct section *strtab, const char *str);
struct symbol *elf_create_symbol(struct elf *elf, const char *name,
struct section *sec, unsigned int bind,
unsigned int type, unsigned long offset,
@ -1100,11 +1099,9 @@ struct elf *elf_open_read(const char *name, int flags)
return NULL;
}
static int elf_add_string(struct elf *elf, struct section *strtab, const char *str)
unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str)
{
Elf_Data *data;
Elf_Scn *s;
int len;
unsigned int offset;
if (!strtab)
strtab = find_section_by_name(elf, ".strtab");
@ -1113,28 +1110,59 @@ static int elf_add_string(struct elf *elf, struct section *strtab, const char *s
return -1;
}
s = elf_getscn(elf->elf, strtab->idx);
if (!strtab->sh.sh_addralign) {
ERROR("'%s': invalid sh_addralign", strtab->name);
return -1;
}
offset = ALIGN_UP(strtab->sh.sh_size, strtab->sh.sh_addralign);
if (!elf_add_data(elf, strtab, str, strlen(str) + 1))
return -1;
return offset;
}
void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_t size)
{
unsigned long offset;
Elf_Scn *s;
if (!sec->sh.sh_addralign) {
ERROR("'%s': invalid sh_addralign", sec->name);
return NULL;
}
s = elf_getscn(elf->elf, sec->idx);
if (!s) {
ERROR_ELF("elf_getscn");
return -1;
return NULL;
}
data = elf_newdata(s);
if (!data) {
sec->data = elf_newdata(s);
if (!sec->data) {
ERROR_ELF("elf_newdata");
return -1;
return NULL;
}
data->d_buf = strdup(str);
data->d_size = strlen(str) + 1;
data->d_align = 1;
sec->data->d_buf = calloc(1, size);
if (!sec->data->d_buf) {
ERROR_GLIBC("calloc");
return NULL;
}
len = strtab->sh.sh_size;
strtab->sh.sh_size += data->d_size;
if (data)
memcpy(sec->data->d_buf, data, size);
mark_sec_changed(elf, strtab, true);
sec->data->d_size = size;
sec->data->d_align = 1;
return len;
offset = ALIGN_UP(sec->sh.sh_size, sec->sh.sh_addralign);
sec->sh.sh_size = offset + size;
mark_sec_changed(elf, sec, true);
return sec->data->d_buf;
}
struct section *elf_create_section(struct elf *elf, const char *name,

View File

@ -135,6 +135,10 @@ struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec);
struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig,
size_t size);
void *elf_add_data(struct elf *elf, struct section *sec, const void *data,
size_t size);
unsigned int elf_add_string(struct elf *elf, struct section *strtab, const char *str);
struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
unsigned long offset,
@ -148,9 +152,9 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
struct symbol *sym,
s64 addend);
int elf_write_insn(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len,
const char *insn);
int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset,
unsigned int len, const char *insn);
int elf_write(struct elf *elf);
void elf_close(struct elf *elf);