Commit 243e9638 authored by Josh Poimboeuf's avatar Josh Poimboeuf
Browse files

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: default avatarPetr Mladek <pmladek@suse.com>
Tested-by: default avatarJoe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
parent dd2c29aa
Loading
Loading
Loading
Loading
+64 −50
Original line number Diff line number Diff line
@@ -1138,35 +1138,39 @@ 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);

	if (size) {
		sec->data = elf_newdata(s);
		if (!sec->data) {
			ERROR_ELF("elf_newdata");
@@ -1176,13 +1180,11 @@ struct section *elf_create_section(struct elf *elf, const char *name,
		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,33 +1194,43 @@ 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;

	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)
		if (!shstrtab) {
			shstrtab = find_section_by_name(elf, ".strtab");
			if (!shstrtab) {
		ERROR("can't find .shstrtab or .strtab section");
				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));
	}

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,
struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
					unsigned int reloc_nr)
{
	struct section *rsec;
@@ -1232,23 +1244,24 @@ 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;

	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;
	rsec->base = sec;
@@ -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;

+6 −1
Original line number Diff line number Diff line
@@ -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,
+5 −1
Original line number Diff line number Diff line
@@ -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;