objtool: Allocate multiple structures with calloc()
authorThomas Weißschuh <linux@weissschuh.net>
Tue, 27 Dec 2022 16:00:59 +0000 (16:00 +0000)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Wed, 1 Feb 2023 17:15:23 +0000 (09:15 -0800)
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@weissschuh.net>
Link: https://lore.kernel.org/r/20221216-objtool-memory-v2-3-17968f85a464@weissschuh.net
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
tools/objtool/elf.c
tools/objtool/include/objtool/elf.h

index 64443a7f4bbf9f1b35ff858233f24d7927c6a21d..6806ce01d933470b2138d2b659946af18ea76a5e 100644 (file)
@@ -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);
 }
index bb60fd42b46f48553eb9013d0e5e9477717f6fac..1c90f0ac0d531568e03f59a9f10751cfaaf497fc 100644 (file)
@@ -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