[tip: objtool/core] objtool: Allocate multiple structures with calloc()

From: tip-bot2 for Thomas Weißschuh
Date: Wed Feb 01 2023 - 11:26:50 EST


The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 389244804db54977b9316f0dc027ab69b3c1e8bf
Gitweb: https://git.kernel.org/tip/389244804db54977b9316f0dc027ab69b3c1e8bf
Author: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
AuthorDate: Tue, 27 Dec 2022 16:00:59
Committer: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
CommitterDate: Mon, 30 Jan 2023 16:28:19 -08:00

objtool: Allocate multiple structures with calloc()

By using calloc() instead of malloc() in a loop, libc does not have to
keep around bookkeeping information for each single structure.

This reduces maximum memory usage while processing vmlinux.o from
3153325 KB to 3035668 KB (-3.7%) on my notebooks "localmodconfig".

Note this introduces memory leaks, because some additional structs get
added to the lists later after reading the symbols and sections from the
original object. Luckily we don't really care about memory leaks in
objtool.

Signed-off-by: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20221216-objtool-memory-v2-3-17968f85a464@xxxxxxxxxxxxxx
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
tools/objtool/elf.c | 42 ++++++++++++++--------------
tools/objtool/include/objtool/elf.h | 4 +++-
2 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 64443a7..6806ce0 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -284,13 +284,13 @@ static int read_sections(struct elf *elf)
!elf_alloc_hash(section_name, sections_nr))
return -1;

+ elf->section_data = calloc(sections_nr, sizeof(*sec));
+ if (!elf->section_data) {
+ perror("calloc");
+ return -1;
+ }
for (i = 0; i < sections_nr; i++) {
- sec = malloc(sizeof(*sec));
- if (!sec) {
- perror("malloc");
- return -1;
- }
- memset(sec, 0, sizeof(*sec));
+ sec = &elf->section_data[i];

INIT_LIST_HEAD(&sec->symbol_list);
INIT_LIST_HEAD(&sec->reloc_list);
@@ -422,13 +422,13 @@ static int read_symbols(struct elf *elf)
!elf_alloc_hash(symbol_name, symbols_nr))
return -1;

+ elf->symbol_data = calloc(symbols_nr, sizeof(*sym));
+ if (!elf->symbol_data) {
+ perror("calloc");
+ return -1;
+ }
for (i = 0; i < symbols_nr; i++) {
- sym = malloc(sizeof(*sym));
- if (!sym) {
- perror("malloc");
- return -1;
- }
- memset(sym, 0, sizeof(*sym));
+ sym = &elf->symbol_data[i];

sym->idx = i;

@@ -918,13 +918,13 @@ static int read_relocs(struct elf *elf)
sec->base->reloc = sec;

nr_reloc = 0;
+ sec->reloc_data = calloc(sec->sh.sh_size / sec->sh.sh_entsize, sizeof(*reloc));
+ if (!sec->reloc_data) {
+ perror("calloc");
+ return -1;
+ }
for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
- reloc = malloc(sizeof(*reloc));
- if (!reloc) {
- perror("malloc");
- return -1;
- }
- memset(reloc, 0, sizeof(*reloc));
+ reloc = &sec->reloc_data[i];
switch (sec->sh.sh_type) {
case SHT_REL:
if (read_rel_reloc(sec, i, reloc, &symndx))
@@ -1453,16 +1453,16 @@ void elf_close(struct elf *elf)
list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
list_del(&sym->list);
hash_del(&sym->hash);
- free(sym);
}
list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
list_del(&reloc->list);
hash_del(&reloc->hash);
- free(reloc);
}
list_del(&sec->list);
- free(sec);
+ free(sec->reloc_data);
}

+ free(elf->symbol_data);
+ free(elf->section_data);
free(elf);
}
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index bb60fd4..1c90f0a 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -39,6 +39,7 @@ struct section {
char *name;
int idx;
bool changed, text, rodata, noinstr, init, truncate;
+ struct reloc *reloc_data;
};

struct symbol {
@@ -104,6 +105,9 @@ struct elf {
struct hlist_head *section_hash;
struct hlist_head *section_name_hash;
struct hlist_head *reloc_hash;
+
+ struct section *section_data;
+ struct symbol *symbol_data;
};

#define OFFSET_STRIDE_BITS 4