2023-05-30 17:32:10

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 00/22] objtool: Reduce memory usage with CONFIG_DEBUG_INFO

DWARF uses a LOT of relocations, causing objtool to need a LOT of memory
for processing vmlinux.o.

In the worst case of an allyesconfig+CONFIG_DEBUG_INFO kernel, DWARF
creates almost 200 million relocations, ballooning objtool's peak heap
usage to 53GB. These patches reduce that to 25GB.

On a distro-type kernel with kernel IBT enabled, they reduce objtool's
peak heap usage from 4.2GB to 2.8GB.

They also improve the runtime significantly (from 2m50s to 1m54s on my
system with allyesconfig+CONFIG_DEBUG_INFO), though most of that comes
from fixing the size calculation for reloc_hash.

Josh Poimboeuf (22):
objtool: Tidy elf.h
objtool: Remove flags argument from elf_create_section()
objtool: Improve reloc naming
objtool: Consolidate rel/rela handling
objtool: Fix reloc_hash size
objtool: Add mark_sec_changed()
objtool: Add elf_create_section_pair()
objtool: Keep GElf_Rel[a] structs synced
objtool: Don't free memory in elf_close()
objtool: Add for_each_reloc()
objtool: Allocate relocs in advance for new rela sections
objtool: Get rid of reloc->list
objtool: Get rid of reloc->idx
objtool: Get rid of reloc->offset
objtool: Get rid of reloc->type
objtool: Get rid of reloc->addend
objtool: Get rid of reloc->jump_table_start
objtool: Shrink reloc->sym_reloc_entry
objtool: Shrink elf hash nodes
objtool: Get rid of reloc->rel[a]
objtool: Free insns when done
objtool: Skip reading DWARF section data

tools/objtool/arch/powerpc/include/arch/elf.h | 11 +-
tools/objtool/arch/x86/decode.c | 6 +-
tools/objtool/arch/x86/include/arch/elf.h | 11 +-
tools/objtool/arch/x86/special.c | 6 +-
tools/objtool/check.c | 429 +++++++-------
tools/objtool/elf.c | 537 +++++++-----------
tools/objtool/include/objtool/elf.h | 326 ++++++++---
tools/objtool/orc_gen.c | 8 +-
tools/objtool/special.c | 4 +-
9 files changed, 698 insertions(+), 640 deletions(-)

--
2.40.1



2023-05-30 17:32:20

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 21/22] objtool: Free insns when done

Free the decoded instructions as they're no longer needed after this
point. This frees up a big chunk of heap, which will come handy when
skipping the reading of DWARF section data.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/check.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 65c59b0b1e96..80d3a97e442b 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4587,6 +4587,34 @@ static int disas_warned_funcs(struct objtool_file *file)
return 0;
}

+struct insn_chunk {
+ void *addr;
+ struct insn_chunk *next;
+};
+
+/*
+ * Reduce peak RSS usage by freeing insns memory before writing the ELF file,
+ * which can trigger more allocations for .debug_* sections whose data hasn't
+ * been read yet.
+ */
+static void free_insns(struct objtool_file *file)
+{
+ struct instruction *insn;
+ struct insn_chunk *chunks = NULL, *chunk;
+
+ for_each_insn(file, insn) {
+ if (!insn->idx) {
+ chunk = malloc(sizeof(*chunk));
+ chunk->addr = insn;
+ chunk->next = chunks;
+ chunks = chunk;
+ }
+ }
+
+ for (chunk = chunks; chunk; chunk = chunk->next)
+ free(chunk->addr);
+}
+
int check(struct objtool_file *file)
{
int ret, warnings = 0;
@@ -4731,6 +4759,8 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ free_insns(file);
+
if (opts.verbose)
disas_warned_funcs(file);

--
2.40.1


2023-05-30 17:32:21

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 12/22] objtool: Get rid of reloc->list

Now that all relocs are allocated in an array, the linked list is no
longer needed.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 49.02G
- After: peak heap memory consumption: 45.56G

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/elf.c | 32 ++++++++++++-----------------
tools/objtool/include/objtool/elf.h | 18 +++++++++++-----
2 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 5f69d4590117..19ac53ad76ee 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -293,7 +293,6 @@ static int read_sections(struct elf *elf)
sec = &elf->section_data[i];

INIT_LIST_HEAD(&sec->symbol_list);
- INIT_LIST_HEAD(&sec->reloc_list);

s = elf_getscn(elf->elf, i);
if (!s) {
@@ -333,7 +332,7 @@ static int read_sections(struct elf *elf)
elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));

if (is_reloc_sec(sec))
- elf->num_relocs += sec->sh.sh_size / sec->sh.sh_entsize;
+ elf->num_relocs += sec_num_entries(sec);
}

if (opts.stats) {
@@ -407,7 +406,7 @@ static int read_symbols(struct elf *elf)
if (symtab_shndx)
shndx_data = symtab_shndx->data;

- symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
+ symbols_nr = sec_num_entries(symtab);
} else {
/*
* A missing symbol table is actually possible if it's an empty
@@ -701,7 +700,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
return NULL;
}

- new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize;
+ new_idx = sec_num_entries(symtab);

if (GELF_ST_BIND(sym->sym.st_info) != STB_LOCAL)
goto non_local;
@@ -816,13 +815,13 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
{
struct reloc *reloc, empty = { 0 };

- if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
- WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
- __func__, reloc_idx, rsec->name, rsec->sh.sh_size);
+ if (reloc_idx >= sec_num_entries(rsec)) {
+ WARN("%s: bad reloc_idx %u for %s with %d relocs",
+ __func__, reloc_idx, rsec->name, sec_num_entries(rsec));
return NULL;
}

- reloc = &rsec->reloc_data[reloc_idx];
+ reloc = &rsec->relocs[reloc_idx];

if (memcmp(reloc, &empty, sizeof(empty))) {
WARN("%s: %s: reloc %d already initialized!",
@@ -841,7 +840,6 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
return NULL;

list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &rsec->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));

return reloc;
@@ -944,14 +942,13 @@ static int read_relocs(struct elf *elf)
rsec->base->rsec = rsec;

nr_reloc = 0;
- rsec->reloc_data = calloc(rsec->sh.sh_size / rsec->sh.sh_entsize,
- sizeof(*reloc));
- if (!rsec->reloc_data) {
+ rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
+ if (!rsec->relocs) {
perror("calloc");
return -1;
}
- for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) {
- reloc = &rsec->reloc_data[i];
+ for (i = 0; i < sec_num_entries(rsec); i++) {
+ reloc = &rsec->relocs[i];

if (read_reloc(rsec, i, reloc))
return -1;
@@ -967,7 +964,6 @@ static int read_relocs(struct elf *elf)
}

list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &rsec->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));

nr_reloc++;
@@ -1093,7 +1089,6 @@ struct section *elf_create_section(struct elf *elf, const char *name,
memset(sec, 0, sizeof(*sec));

INIT_LIST_HEAD(&sec->symbol_list);
- INIT_LIST_HEAD(&sec->reloc_list);

s = elf_newscn(elf->elf);
if (!s) {
@@ -1186,9 +1181,8 @@ static struct section *elf_create_rela_section(struct elf *elf,
rsec->sh.sh_info = sec->idx;
rsec->sh.sh_flags = SHF_INFO_LINK;

- rsec->reloc_data = calloc(rsec->sh.sh_size / rsec->sh.sh_entsize,
- sizeof(struct reloc));
- if (!rsec->reloc_data) {
+ rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
+ if (!rsec->relocs) {
perror("calloc");
return NULL;
}
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index a938cb1d4172..a09da208ddb8 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -33,14 +33,13 @@ struct section {
GElf_Shdr sh;
struct rb_root_cached symbol_tree;
struct list_head symbol_list;
- struct list_head reloc_list;
struct section *base, *rsec;
struct symbol *sym;
Elf_Data *data;
char *name;
int idx;
bool _changed, text, rodata, noinstr, init, truncate;
- struct reloc *reloc_data;
+ struct reloc *relocs;
};

struct symbol {
@@ -68,7 +67,6 @@ struct symbol {
};

struct reloc {
- struct list_head list;
struct hlist_node hash;
union {
GElf_Rela rela;
@@ -197,6 +195,11 @@ static inline void mark_sec_changed(struct elf *elf, struct section *sec,
elf->changed |= changed;
}

+static inline unsigned int sec_num_entries(struct section *sec)
+{
+ return sec->sh.sh_size / sec->sh.sh_entsize;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

@@ -210,10 +213,15 @@ static inline void mark_sec_changed(struct elf *elf, struct section *sec,
sec_for_each_sym(__sec, sym)

#define for_each_reloc(rsec, reloc) \
- list_for_each_entry(reloc, &rsec->reloc_list, list)
+ for (int __i = 0, __fake = 1; __fake; __fake = 0) \
+ for (reloc = rsec->relocs; \
+ __i < sec_num_entries(rsec); \
+ __i++, reloc++)

#define for_each_reloc_from(rsec, reloc) \
- list_for_each_entry_from(reloc, &rsec->reloc_list, list)
+ for (int __i = reloc->idx; \
+ __i < sec_num_entries(rsec); \
+ __i++, reloc++)

#define OFFSET_STRIDE_BITS 4
#define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
--
2.40.1


2023-05-30 17:32:24

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 19/22] objtool: Shrink elf hash nodes

Instead of using hlist for the 'struct elf' hashes, use a custom
single-linked list scheme.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 36.89G
- After: peak heap memory consumption: 35.12G

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/elf.c | 52 ++++++++++++++++++++++++-----
tools/objtool/include/objtool/elf.h | 24 +++++++------
2 files changed, 58 insertions(+), 18 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 4b0de0e56068..04038b1324cf 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -32,16 +32,52 @@ static inline u32 str_hash(const char *str)
#define __elf_table(name) (elf->name##_hash)
#define __elf_bits(name) (elf->name##_bits)

-#define elf_hash_add(name, node, key) \
- hlist_add_head(node, &__elf_table(name)[hash_min(key, __elf_bits(name))])
+#define __elf_table_entry(name, key) \
+ __elf_table(name)[hash_min(key, __elf_bits(name))]

-#define elf_hash_for_each_possible(name, obj, member, key) \
- hlist_for_each_entry(obj, &__elf_table(name)[hash_min(key, __elf_bits(name))], member)
+#define elf_hash_add(name, node, key) \
+({ \
+ struct elf_hash_node *__node = node; \
+ __node->next = __elf_table_entry(name, key); \
+ __elf_table_entry(name, key) = __node; \
+})
+
+static inline void __elf_hash_del(struct elf_hash_node *node,
+ struct elf_hash_node **head)
+{
+ struct elf_hash_node *cur, *prev;
+
+ if (node == *head) {
+ *head = node->next;
+ return;
+ }
+
+ for (prev = NULL, cur = *head; cur; prev = cur, cur = cur->next) {
+ if (cur == node) {
+ prev->next = cur->next;
+ break;
+ }
+ }
+}
+
+#define elf_hash_del(name, node, key) \
+ __elf_hash_del(node, &__elf_table_entry(name, key))
+
+#define elf_list_entry(ptr, type, member) \
+({ \
+ typeof(ptr) __ptr = (ptr); \
+ __ptr ? container_of(__ptr, type, member) : NULL; \
+})
+
+#define elf_hash_for_each_possible(name, obj, member, key) \
+ for (obj = elf_list_entry(__elf_table_entry(name, key), typeof(*obj), member); \
+ obj; \
+ obj = elf_list_entry(obj->member.next, typeof(*(obj)), member))

#define elf_alloc_hash(name, size) \
({ \
__elf_bits(name) = max(10, ilog2(size)); \
- __elf_table(name) = mmap(NULL, sizeof(struct hlist_head) << __elf_bits(name), \
+ __elf_table(name) = mmap(NULL, sizeof(struct elf_hash_node *) << __elf_bits(name), \
PROT_READ|PROT_WRITE, \
MAP_PRIVATE|MAP_ANON, -1, 0); \
if (__elf_table(name) == (void *)-1L) { \
@@ -713,10 +749,10 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
first_non_local = symtab->sh.sh_info;
old = find_symbol_by_index(elf, first_non_local);
if (old) {
- old->idx = new_idx;

- hlist_del(&old->hash);
- elf_hash_add(symbol, &old->hash, old->idx);
+ elf_hash_del(symbol, &old->hash, old->idx);
+ elf_hash_add(symbol, &old->hash, new_idx);
+ old->idx = new_idx;

if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
WARN("elf_update_symbol move");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 7b808ac3156c..03a9040f696c 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -26,10 +26,14 @@
#define ELF_C_READ_MMAP ELF_C_READ
#endif

+struct elf_hash_node {
+ struct elf_hash_node *next;
+};
+
struct section {
struct list_head list;
- struct hlist_node hash;
- struct hlist_node name_hash;
+ struct elf_hash_node hash;
+ struct elf_hash_node name_hash;
GElf_Shdr sh;
struct rb_root_cached symbol_tree;
struct list_head symbol_list;
@@ -45,8 +49,8 @@ struct section {
struct symbol {
struct list_head list;
struct rb_node node;
- struct hlist_node hash;
- struct hlist_node name_hash;
+ struct elf_hash_node hash;
+ struct elf_hash_node name_hash;
GElf_Sym sym;
struct section *sec;
char *name;
@@ -67,7 +71,7 @@ struct symbol {
};

struct reloc {
- struct hlist_node hash;
+ struct elf_hash_node hash;
union {
GElf_Rela rela;
GElf_Rel rel;
@@ -93,11 +97,11 @@ struct elf {
int section_name_bits;
int reloc_bits;

- struct hlist_head *symbol_hash;
- struct hlist_head *symbol_name_hash;
- struct hlist_head *section_hash;
- struct hlist_head *section_name_hash;
- struct hlist_head *reloc_hash;
+ struct elf_hash_node **symbol_hash;
+ struct elf_hash_node **symbol_name_hash;
+ struct elf_hash_node **section_hash;
+ struct elf_hash_node **section_name_hash;
+ struct elf_hash_node **reloc_hash;

struct section *section_data;
struct symbol *symbol_data;
--
2.40.1


2023-05-30 17:32:26

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 14/22] objtool: Get rid of reloc->offset

Get the offset from the embedded GElf_Rel[a] struct.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 43.83G
- After: peak heap memory consumption: 42.10G

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/check.c | 14 +++++++-------
tools/objtool/elf.c | 10 +++++-----
tools/objtool/include/objtool/elf.h | 8 ++++++--
3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 1355e6fec7d6..440c326121d4 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -510,11 +510,11 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)
if (func->type == STT_SECTION)
func = find_symbol_by_offset(reloc->sym->sec, reloc->addend);

- idx = (reloc->offset - sym->offset) / sizeof(unsigned long);
+ idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long);

objtool_pv_add(file, idx, func);

- off = reloc->offset + 1;
+ off = reloc_offset(reloc) + 1;
if (off > end)
break;
}
@@ -1997,7 +1997,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;

/* Make sure the table entries are consecutive: */
- if (prev_offset && reloc->offset != prev_offset + 8)
+ if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
break;

/* Detect function pointers from contiguous objects: */
@@ -2022,7 +2022,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
alt->insn = dest_insn;
alt->next = insn->alts;
insn->alts = alt;
- prev_offset = reloc->offset;
+ prev_offset = reloc_offset(reloc);
}

if (!prev_offset) {
@@ -4257,8 +4257,8 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
for (reloc = insn_reloc(file, insn);
reloc;
reloc = find_reloc_by_dest_range(file->elf, insn->sec,
- reloc->offset + 1,
- (insn->offset + insn->len) - (reloc->offset + 1))) {
+ reloc_offset(reloc) + 1,
+ (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) {

/*
* static_call_update() references the trampoline, which
@@ -4341,7 +4341,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file,
return 0;

WARN_FUNC("data relocation to !ENDBR: %s",
- reloc->sec->base, reloc->offset,
+ reloc->sec->base, reloc_offset(reloc),
offstr(dest->sec, dest->offset));

return 1;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 70c801254566..2b45460225d1 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -246,8 +246,9 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se
if (reloc->sec != rsec)
continue;

- if (reloc->offset >= offset && reloc->offset < offset + len) {
- if (!r || reloc->offset < r->offset)
+ if (reloc_offset(reloc) >= offset &&
+ reloc_offset(reloc) < offset + len) {
+ if (!r || reloc_offset(reloc) < reloc_offset(r))
r = reloc;
}
}
@@ -830,11 +831,12 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
}

reloc->sec = rsec;
- reloc->offset = offset;
reloc->type = type;
reloc->sym = sym;
reloc->addend = addend;

+ reloc->rel.r_offset = offset;
+
if (elf_write_reloc(elf, reloc))
return NULL;

@@ -908,7 +910,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
return -1;
}

- reloc->offset = reloc->rel.r_offset;
reloc->type = GELF_R_TYPE(reloc->rel.r_info);
reloc->addend = rela ? reloc->rela.r_addend : 0;

@@ -1230,7 +1231,6 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc)
struct section *rsec = reloc->sec;
int ret;

- reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);

if (rsec->sh.sh_type == SHT_RELA) {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 2a14da633d56..2070860a099e 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -75,7 +75,6 @@ struct reloc {
struct section *sec;
struct symbol *sym;
struct list_head sym_reloc_entry;
- unsigned long offset;
s64 addend;
unsigned int type;
bool jump_table_start;
@@ -204,6 +203,11 @@ static inline unsigned int reloc_idx(struct reloc *reloc)
return reloc - reloc->sec->relocs;
}

+static inline unsigned long reloc_offset(struct reloc *reloc)
+{
+ return reloc->rel.r_offset;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

@@ -253,7 +257,7 @@ static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)

static inline u32 reloc_hash(struct reloc *reloc)
{
- return sec_offset_hash(reloc->sec, reloc->offset);
+ return sec_offset_hash(reloc->sec, reloc_offset(reloc));
}

#endif /* _OBJTOOL_ELF_H */
--
2.40.1


2023-05-30 17:32:41

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 07/22] objtool: Add elf_create_section_pair()

When creating an annotation section, allocate the reloc section data at
the beginning. This simplifies the data model a bit and also saves
memory due to the removal of malloc() in elf_rebuild_reloc_section().

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 53.49G
- After: peak heap memory consumption: 49.02G

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/arch/powerpc/include/arch/elf.h | 11 +-
tools/objtool/arch/x86/include/arch/elf.h | 11 +-
tools/objtool/check.c | 129 ++++++---------
tools/objtool/elf.c | 151 +++++++++++-------
tools/objtool/include/objtool/elf.h | 33 +++-
tools/objtool/orc_gen.c | 6 +-
6 files changed, 184 insertions(+), 157 deletions(-)

diff --git a/tools/objtool/arch/powerpc/include/arch/elf.h b/tools/objtool/arch/powerpc/include/arch/elf.h
index 73f9ae172fe5..66814fa28024 100644
--- a/tools/objtool/arch/powerpc/include/arch/elf.h
+++ b/tools/objtool/arch/powerpc/include/arch/elf.h
@@ -1,10 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-
#ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF

-#define R_NONE R_PPC_NONE
-#define R_ABS64 R_PPC64_ADDR64
-#define R_ABS32 R_PPC_ADDR32
+#define R_NONE R_PPC_NONE
+#define R_ABS64 R_PPC64_ADDR64
+#define R_ABS32 R_PPC_ADDR32
+#define R_DATA32 R_PPC_REL32
+#define R_DATA64 R_PPC64_REL64
+#define R_TEXT32 R_PPC_REL32
+#define R_TEXT64 R_PPC64_REL32

#endif /* _OBJTOOL_ARCH_ELF */
diff --git a/tools/objtool/arch/x86/include/arch/elf.h b/tools/objtool/arch/x86/include/arch/elf.h
index ac14987cf687..7131f7f51a4e 100644
--- a/tools/objtool/arch/x86/include/arch/elf.h
+++ b/tools/objtool/arch/x86/include/arch/elf.h
@@ -1,8 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF

-#define R_NONE R_X86_64_NONE
-#define R_ABS64 R_X86_64_64
-#define R_ABS32 R_X86_64_32
+#define R_NONE R_X86_64_NONE
+#define R_ABS32 R_X86_64_32
+#define R_ABS64 R_X86_64_64
+#define R_DATA32 R_X86_64_PC32
+#define R_DATA64 R_X86_64_PC32
+#define R_TEXT32 R_X86_64_PC32
+#define R_TEXT64 R_X86_64_PC32

#endif /* _OBJTOOL_ARCH_ELF */
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index b6d0cb24085b..88f54bb1b01c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -8,7 +8,6 @@
#include <inttypes.h>
#include <sys/mman.h>

-#include <arch/elf.h>
#include <objtool/builtin.h>
#include <objtool/cfi.h>
#include <objtool/arch.h>
@@ -655,8 +654,8 @@ static int add_dead_ends(struct objtool_file *file)

static int create_static_call_sections(struct objtool_file *file)
{
- struct section *sec;
struct static_call_site *site;
+ struct section *sec;
struct instruction *insn;
struct symbol *key_sym;
char *key_name, *tmp;
@@ -676,25 +675,21 @@ static int create_static_call_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->static_call_list, call_node)
idx++;

- sec = elf_create_section(file->elf, ".static_call_sites",
- sizeof(struct static_call_site), idx);
+ sec = elf_create_section_pair(file->elf, ".static_call_sites",
+ sizeof(*site), idx, idx * 2);
if (!sec)
return -1;

- /* Allow modules to set the low bits of static_call_site::key */
+ /* Allow modules to modify the low bits of static_call_site::key */
sec->sh.sh_flags |= SHF_WRITE;

idx = 0;
list_for_each_entry(insn, &file->static_call_list, call_node) {

- site = (struct static_call_site *)sec->data->d_buf + idx;
- memset(site, 0, sizeof(struct static_call_site));
-
/* populate reloc for 'addr' */
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(struct static_call_site),
- R_X86_64_PC32,
- insn->sec, insn->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(*site), idx * 2,
+ insn->sec, insn->offset))
return -1;

/* find key symbol */
@@ -734,10 +729,10 @@ static int create_static_call_sections(struct objtool_file *file)
free(key_name);

/* populate reloc for 'key' */
- if (elf_add_reloc(file->elf, sec,
- idx * sizeof(struct static_call_site) + 4,
- R_X86_64_PC32, key_sym,
- is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
+ if (!elf_init_reloc_data_sym(file->elf, sec,
+ idx * sizeof(*site) + 4,
+ (idx * 2) + 1, key_sym,
+ is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
return -1;

idx++;
@@ -765,26 +760,18 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".retpoline_sites",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .retpoline_sites");
+ sec = elf_create_section_pair(file->elf, ".retpoline_sites",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {

- int *site = (int *)sec->data->d_buf + idx;
- *site = 0;
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .retpoline_sites");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -811,26 +798,18 @@ static int create_return_sites_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".return_sites",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .return_sites");
+ sec = elf_create_section_pair(file->elf, ".return_sites",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->return_thunk_list, call_node) {

- int *site = (int *)sec->data->d_buf + idx;
- *site = 0;
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .return_sites");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -863,12 +842,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".ibt_endbr_seal",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .ibt_endbr_seal");
+ sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->endbr_list, call_node) {
@@ -883,13 +860,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
!strcmp(sym->name, "cleanup_module")))
WARN("%s(): not an indirect call target", sym->name);

- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .ibt_endbr_seal");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -901,7 +875,6 @@ static int create_cfi_sections(struct objtool_file *file)
{
struct section *sec;
struct symbol *sym;
- unsigned int *loc;
int idx;

sec = find_section_by_name(file->elf, ".cfi_sites");
@@ -922,7 +895,8 @@ static int create_cfi_sections(struct objtool_file *file)
idx++;
}

- sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx);
+ sec = elf_create_section_pair(file->elf, ".cfi_sites",
+ sizeof(unsigned int), idx, idx);
if (!sec)
return -1;

@@ -934,13 +908,9 @@ static int create_cfi_sections(struct objtool_file *file)
if (strncmp(sym->name, "__cfi_", 6))
continue;

- loc = (unsigned int *)sec->data->d_buf + idx;
- memset(loc, 0, sizeof(unsigned int));
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(unsigned int),
- R_X86_64_PC32,
- sym->sec, sym->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(unsigned int), idx,
+ sym->sec, sym->offset))
return -1;

idx++;
@@ -970,7 +940,8 @@ static int create_mcount_loc_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
idx++;

- sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
+ sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size,
+ idx, idx);
if (!sec)
return -1;

@@ -978,17 +949,17 @@ static int create_mcount_loc_sections(struct objtool_file *file)

idx = 0;
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
- void *loc;

- loc = sec->data->d_buf + idx;
- memset(loc, 0, addr_size);
+ struct reloc *reloc;

- if (elf_add_reloc_to_insn(file->elf, sec, idx,
- addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
- insn->sec, insn->offset))
+ reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx,
+ insn->sec, insn->offset);
+ if (!reloc)
return -1;

- idx += addr_size;
+ reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32;
+
+ idx++;
}

return 0;
@@ -998,7 +969,6 @@ static int create_direct_call_sections(struct objtool_file *file)
{
struct instruction *insn;
struct section *sec;
- unsigned int *loc;
int idx;

sec = find_section_by_name(file->elf, ".call_sites");
@@ -1015,20 +985,17 @@ static int create_direct_call_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->call_list, call_node)
idx++;

- sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx);
+ sec = elf_create_section_pair(file->elf, ".call_sites",
+ sizeof(unsigned int), idx, idx);
if (!sec)
return -1;

idx = 0;
list_for_each_entry(insn, &file->call_list, call_node) {

- loc = (unsigned int *)sec->data->d_buf + idx;
- memset(loc, 0, sizeof(unsigned int));
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(unsigned int),
- R_X86_64_PC32,
- insn->sec, insn->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(unsigned int), idx,
+ insn->sec, insn->offset))
return -1;

idx++;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 67967c231972..5cbc9d578a45 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -533,41 +533,6 @@ static int read_symbols(struct elf *elf)
return -1;
}

-static struct section *elf_create_rela_section(struct elf *elf,
- struct section *sec);
-
-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
- unsigned int type, struct symbol *sym, s64 addend)
-{
- struct reloc *reloc;
-
- if (!sec->rsec && !elf_create_rela_section(elf, sec))
- return -1;
-
- reloc = malloc(sizeof(*reloc));
- if (!reloc) {
- perror("malloc");
- return -1;
- }
- memset(reloc, 0, sizeof(*reloc));
-
- reloc->sec = sec->rsec;
- reloc->offset = offset;
- reloc->type = type;
- reloc->sym = sym;
- reloc->addend = addend;
-
- list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &sec->rsec->reloc_list);
- elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
-
- sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize;
-
- mark_sec_changed(elf, sec->rsec, true);
-
- return 0;
-}
-
/*
* Ensure that any reloc section containing references to @sym is marked
* changed such that it will get re-generated in elf_rebuild_reloc_sections()
@@ -841,13 +806,57 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
return sym;
}

-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
- unsigned long offset, unsigned int type,
- struct section *insn_sec, unsigned long insn_off)
+static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
+ unsigned int reloc_idx,
+ unsigned long offset, struct symbol *sym,
+ s64 addend, unsigned int type)
+{
+ struct reloc *reloc;
+
+ if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
+ WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
+ __func__, reloc_idx, rsec->name, rsec->sh.sh_size);
+ return NULL;
+ }
+
+ reloc = malloc(sizeof(*reloc));
+ if (!reloc) {
+ perror("malloc");
+ return NULL;
+ }
+ memset(reloc, 0, sizeof(*reloc));
+
+ reloc->idx = reloc_idx;
+ reloc->sec = rsec;
+ reloc->offset = offset;
+ reloc->type = type;
+ reloc->sym = sym;
+ reloc->addend = addend;
+
+ list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
+ list_add_tail(&reloc->list, &rsec->reloc_list);
+ elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
+
+ mark_sec_changed(elf, rsec, true);
+
+ return reloc;
+}
+
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct section *insn_sec,
+ unsigned long insn_off)
{
struct symbol *sym = insn_sec->sym;
int addend = insn_off;

+ if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
+ WARN("bad call to %s() for data symbol %s",
+ __func__, sym->name);
+ return NULL;
+ }
+
if (!sym) {
/*
* Due to how weak functions work, we must use section based
@@ -857,12 +866,29 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
*/
sym = elf_create_section_symbol(elf, insn_sec);
if (!sym)
- return -1;
+ return NULL;

insn_sec->sym = sym;
}

- return elf_add_reloc(elf, sec, offset, type, sym, addend);
+ return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+ elf_text_rela_type(elf));
+}
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct symbol *sym,
+ s64 addend)
+{
+ if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
+ WARN("bad call to %s() for text symbol %s",
+ __func__, sym->name);
+ return NULL;
+ }
+
+ return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+ elf_data_rela_type(elf));
}

static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
@@ -1048,7 +1074,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
}

struct section *elf_create_section(struct elf *elf, const char *name,
- size_t entsize, int nr)
+ size_t entsize, unsigned int nr)
{
struct section *sec, *shstrtab;
size_t size = entsize * nr;
@@ -1129,7 +1155,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
}

static struct section *elf_create_rela_section(struct elf *elf,
- struct section *sec)
+ struct section *sec,
+ unsigned int reloc_nr)
{
struct section *rsec;
char *rsec_name;
@@ -1142,46 +1169,50 @@ 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), 0);
+ rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
free(rsec_name);
if (!rsec)
return NULL;

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

+ sec->rsec = rsec;
+ rsec->base = sec;
+
return rsec;
}

+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr,
+ unsigned int reloc_nr)
+{
+ struct section *sec;
+
+ sec = elf_create_section(elf, name, entsize, nr);
+ if (!sec)
+ return NULL;
+
+ if (!elf_create_rela_section(elf, sec, reloc_nr))
+ return NULL;
+
+ return sec;
+}
+
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
{
- bool rela = rsec->sh.sh_type == SHT_RELA;
struct reloc *reloc;
int idx = 0, ret;
- void *buf;
-
- /* Allocate a buffer for relocations */
- buf = malloc(rsec->sh.sh_size);
- if (!buf) {
- perror("malloc");
- return -1;
- }
-
- rsec->data->d_buf = buf;
- rsec->data->d_size = rsec->sh.sh_size;
- rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;

idx = 0;
list_for_each_entry(reloc, &rsec->reloc_list, list) {
reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- if (rela) {
+ if (rsec->sh.sh_type == SHT_RELA) {
reloc->rela.r_addend = reloc->addend;
ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
} else {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 56b66ff91943..74f63934afd3 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -111,15 +111,26 @@ 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, int nr);
+
+struct section *elf_create_section(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr);
+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr,
+ unsigned int reloc_nr);

struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);

-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
- unsigned int type, struct symbol *sym, s64 addend);
-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
- unsigned long offset, unsigned int type,
- struct section *insn_sec, unsigned long insn_off);
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct section *insn_sec,
+ unsigned long insn_off);
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct symbol *sym,
+ s64 addend);

int elf_write_insn(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len,
@@ -159,6 +170,16 @@ static inline size_t elf_rela_size(struct elf *elf)
return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
}

+static inline unsigned int elf_data_rela_type(struct elf *elf)
+{
+ return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
+}
+
+static inline unsigned int elf_text_rela_type(struct elf *elf)
+{
+ return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
+}
+
static inline bool is_reloc_sec(struct section *sec)
{
return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c
index d5f750be7d7d..bae343908867 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/orc_gen.c
@@ -118,8 +118,8 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec,
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);

/* populate reloc for ip */
- if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32,
- insn_sec, insn_off))
+ if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
+ insn_sec, insn_off))
return -1;

return 0;
@@ -242,7 +242,7 @@ int orc_create(struct objtool_file *file)
if (!orc_sec)
return -1;

- sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr);
+ sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);
if (!sec)
return -1;

--
2.40.1


2023-05-30 17:33:22

by Josh Poimboeuf

[permalink] [raw]
Subject: [PATCH 16/22] objtool: Get rid of reloc->addend

Get the addend from the embedded GElf_Rel[a] struct.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 42.10G
- After: peak heap memory consumption: 40.37G

Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/arch/x86/decode.c | 4 +-
tools/objtool/arch/x86/special.c | 2 +-
tools/objtool/check.c | 69 +++++++++++++++++------------
tools/objtool/elf.c | 10 ++---
tools/objtool/include/objtool/elf.h | 6 ++-
tools/objtool/special.c | 4 +-
6 files changed, 53 insertions(+), 42 deletions(-)

diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index ffb12e83b238..2e1caabecb18 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -623,11 +623,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (!immr || strcmp(immr->sym->name, "pv_ops"))
break;

- idx = (immr->addend + 8) / sizeof(void *);
+ idx = (reloc_addend(immr) + 8) / sizeof(void *);

func = disp->sym;
if (disp->sym->type == STT_SECTION)
- func = find_symbol_by_offset(disp->sym->sec, disp->addend);
+ func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
if (!func) {
WARN("no func for pv_ops[]");
return -1;
diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c
index 1a54a249cb50..65f48f35b97e 100644
--- a/tools/objtool/arch/x86/special.c
+++ b/tools/objtool/arch/x86/special.c
@@ -105,7 +105,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
!text_reloc->sym->sec->rodata)
return NULL;

- table_offset = text_reloc->addend;
+ table_offset = reloc_addend(text_reloc);
table_sec = text_reloc->sym->sec;

if (reloc_type(text_reloc) == R_X86_64_PC32)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 1d794d15bc53..12a9e6fb3fe7 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -508,7 +508,8 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)

func = reloc->sym;
if (func->type == STT_SECTION)
- func = find_symbol_by_offset(reloc->sym->sec, reloc->addend);
+ func = find_symbol_by_offset(reloc->sym->sec,
+ reloc_addend(reloc));

idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long);

@@ -582,6 +583,7 @@ static int add_dead_ends(struct objtool_file *file)
struct section *rsec;
struct reloc *reloc;
struct instruction *insn;
+ s64 addend;

/*
* Check for manually annotated dead ends.
@@ -591,23 +593,27 @@ static int add_dead_ends(struct objtool_file *file)
goto reachable;

for_each_reloc(rsec, reloc) {
+
if (reloc->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in %s", rsec->name);
return -1;
}
- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+
+ addend = reloc_addend(reloc);
+
+ insn = find_insn(file, reloc->sym->sec, addend);
if (insn)
insn = prev_insn_same_sec(file, insn);
- else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+ else if (addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}
} else {
WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}

@@ -626,23 +632,27 @@ static int add_dead_ends(struct objtool_file *file)
return 0;

for_each_reloc(rsec, reloc) {
+
if (reloc->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in %s", rsec->name);
return -1;
}
- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+
+ addend = reloc_addend(reloc);
+
+ insn = find_insn(file, reloc->sym->sec, addend);
if (insn)
insn = prev_insn_same_sec(file, insn);
- else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+ else if (addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}
} else {
WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}

@@ -1025,7 +1035,7 @@ static void add_ignores(struct objtool_file *file)
break;

case STT_SECTION:
- func = find_func_by_offset(reloc->sym->sec, reloc->addend);
+ func = find_func_by_offset(reloc->sym->sec, reloc_addend(reloc));
if (!func)
continue;
break;
@@ -1265,7 +1275,7 @@ static int add_ignore_alternatives(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.ignore_alts entry");
return -1;
@@ -1541,7 +1551,7 @@ static int add_jump_destinations(struct objtool_file *file)
dest_off = arch_jump_destination(insn);
} else if (reloc->sym->type == STT_SECTION) {
dest_sec = reloc->sym->sec;
- dest_off = arch_dest_reloc_offset(reloc->addend);
+ dest_off = arch_dest_reloc_offset(reloc_addend(reloc));
} else if (reloc->sym->retpoline_thunk) {
add_retpoline_call(file, insn);
continue;
@@ -1558,7 +1568,7 @@ static int add_jump_destinations(struct objtool_file *file)
} else if (reloc->sym->sec->idx) {
dest_sec = reloc->sym->sec;
dest_off = reloc->sym->sym.st_value +
- arch_dest_reloc_offset(reloc->addend);
+ arch_dest_reloc_offset(reloc_addend(reloc));
} else {
/* non-func asm code jumping to another file */
continue;
@@ -1675,7 +1685,7 @@ static int add_call_destinations(struct objtool_file *file)
}

} else if (reloc->sym->type == STT_SECTION) {
- dest_off = arch_dest_reloc_offset(reloc->addend);
+ dest_off = arch_dest_reloc_offset(reloc_addend(reloc));
dest = find_call_destination(reloc->sym->sec, dest_off);
if (!dest) {
WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx",
@@ -2002,10 +2012,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,

/* Detect function pointers from contiguous objects: */
if (reloc->sym->sec == pfunc->sec &&
- reloc->addend == pfunc->offset)
+ reloc_addend(reloc) == pfunc->offset)
break;

- dest_insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!dest_insn)
break;

@@ -2066,7 +2076,7 @@ static struct reloc *find_jump_table(struct objtool_file *file,
table_reloc = arch_find_switch_table(file, insn);
if (!table_reloc)
continue;
- dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
+ dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;

@@ -2202,7 +2212,7 @@ static int read_unwind_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("can't find insn for unwind_hints[%d]", i);
return -1;
@@ -2265,7 +2275,8 @@ static int read_noendbr_hints(struct objtool_file *file)
return 0;

for_each_reloc(rsec, reloc) {
- insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend);
+ insn = find_insn(file, reloc->sym->sec,
+ reloc->sym->offset + reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.noendbr entry");
return -1;
@@ -2293,7 +2304,7 @@ static int read_retpoline_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.retpoline_safe entry");
return -1;
@@ -2329,7 +2340,7 @@ static int read_instr_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_end entry");
return -1;
@@ -2348,7 +2359,7 @@ static int read_instr_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_begin entry");
return -1;
@@ -2376,7 +2387,7 @@ static int read_validate_unret_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_end entry");
return -1;
@@ -2407,7 +2418,7 @@ static int read_intra_function_calls(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.intra_function_call entry");
return -1;
@@ -3307,7 +3318,7 @@ static inline const char *call_dest_name(struct instruction *insn)

reloc = insn_reloc(NULL, insn);
if (reloc && !strcmp(reloc->sym->name, "pv_ops")) {
- idx = (reloc->addend / sizeof(void *));
+ idx = (reloc_addend(reloc) / sizeof(void *));
snprintf(pvname, sizeof(pvname), "pv_ops[%d]", idx);
return pvname;
}
@@ -3325,7 +3336,7 @@ static bool pv_call_dest(struct objtool_file *file, struct instruction *insn)
if (!reloc || strcmp(reloc->sym->name, "pv_ops"))
return false;

- idx = (arch_dest_reloc_offset(reloc->addend) / sizeof(void *));
+ idx = (arch_dest_reloc_offset(reloc_addend(reloc)) / sizeof(void *));

if (file->pv_ops[idx].clean)
return true;
@@ -4270,9 +4281,9 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
off = reloc->sym->offset;
if (reloc_type(reloc) == R_X86_64_PC32 ||
reloc_type(reloc) == R_X86_64_PLT32)
- off += arch_dest_reloc_offset(reloc->addend);
+ off += arch_dest_reloc_offset(reloc_addend(reloc));
else
- off += reloc->addend;
+ off += reloc_addend(reloc);

dest = find_insn(file, reloc->sym->sec, off);
if (!dest)
@@ -4329,7 +4340,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file,
struct instruction *dest;

dest = find_insn(file, reloc->sym->sec,
- reloc->sym->offset + reloc->addend);
+ reloc->sym->offset + reloc_addend(reloc));
if (!dest)
return 0;

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index be9d24dcdf56..16e019a1762c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -833,10 +833,10 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,

reloc->sec = rsec;
reloc->sym = sym;
- reloc->addend = addend;

reloc->rel.r_offset = offset;
reloc->rel.r_info = GELF_R_INFO(sym->idx, type);
+ reloc->rela.r_addend = addend;

if (elf_write_reloc(elf, reloc))
return NULL;
@@ -911,8 +911,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
return -1;
}

- reloc->addend = rela ? reloc->rela.r_addend : 0;
-
return 0;
}

@@ -1231,12 +1229,10 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc)
struct section *rsec = reloc->sec;
int ret;

- if (rsec->sh.sh_type == SHT_RELA) {
- reloc->rela.r_addend = reloc->addend;
+ if (rsec->sh.sh_type == SHT_RELA)
ret = gelf_update_rela(rsec->data, reloc_idx(reloc), &reloc->rela);
- } else {
+ else
ret = gelf_update_rel(rsec->data, reloc_idx(reloc), &reloc->rel);
- }

if (!ret) {
WARN_ELF("gelf_update_rela");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 41d2149f8bb8..be08b32a93ee 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -75,7 +75,6 @@ struct reloc {
struct section *sec;
struct symbol *sym;
struct list_head sym_reloc_entry;
- s64 addend;
bool jump_table_start;
};

@@ -217,6 +216,11 @@ static inline void set_reloc_type(struct reloc *reloc, int type)
reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type);
}

+static inline s64 reloc_addend(struct reloc *reloc)
+{
+ return reloc->rela.r_addend;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index baa85c31526b..91b1950f5bd8 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -62,7 +62,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
unsigned long *off)
{
*sec = reloc->sym->sec;
- *off = reloc->sym->offset + reloc->addend;
+ *off = reloc->sym->offset + reloc_addend(reloc);
}

static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
@@ -126,7 +126,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
sec, offset + entry->key);
return -1;
}
- alt->key_addend = key_reloc->addend;
+ alt->key_addend = reloc_addend(key_reloc);
}

return 0;
--
2.40.1


Subject: [tip: objtool/core] objtool: Get rid of reloc->list

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

Commit-ID: ebcef730a19ba7ca446169f391d2e51722d68043
Gitweb: https://git.kernel.org/tip/ebcef730a19ba7ca446169f391d2e51722d68043
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:21:04 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:20 -07:00

objtool: Get rid of reloc->list

Now that all relocs are allocated in an array, the linked list is no
longer needed.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 49.02G
- After: peak heap memory consumption: 45.56G

Link: https://lore.kernel.org/r/71e7a2c017dbc46bb497857ec97d67214f832d10.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/elf.c | 32 +++++++++++-----------------
tools/objtool/include/objtool/elf.h | 18 +++++++++++-----
2 files changed, 26 insertions(+), 24 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 5f69d45..19ac53a 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -293,7 +293,6 @@ static int read_sections(struct elf *elf)
sec = &elf->section_data[i];

INIT_LIST_HEAD(&sec->symbol_list);
- INIT_LIST_HEAD(&sec->reloc_list);

s = elf_getscn(elf->elf, i);
if (!s) {
@@ -333,7 +332,7 @@ static int read_sections(struct elf *elf)
elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));

if (is_reloc_sec(sec))
- elf->num_relocs += sec->sh.sh_size / sec->sh.sh_entsize;
+ elf->num_relocs += sec_num_entries(sec);
}

if (opts.stats) {
@@ -407,7 +406,7 @@ static int read_symbols(struct elf *elf)
if (symtab_shndx)
shndx_data = symtab_shndx->data;

- symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
+ symbols_nr = sec_num_entries(symtab);
} else {
/*
* A missing symbol table is actually possible if it's an empty
@@ -701,7 +700,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
return NULL;
}

- new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize;
+ new_idx = sec_num_entries(symtab);

if (GELF_ST_BIND(sym->sym.st_info) != STB_LOCAL)
goto non_local;
@@ -816,13 +815,13 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
{
struct reloc *reloc, empty = { 0 };

- if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
- WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
- __func__, reloc_idx, rsec->name, rsec->sh.sh_size);
+ if (reloc_idx >= sec_num_entries(rsec)) {
+ WARN("%s: bad reloc_idx %u for %s with %d relocs",
+ __func__, reloc_idx, rsec->name, sec_num_entries(rsec));
return NULL;
}

- reloc = &rsec->reloc_data[reloc_idx];
+ reloc = &rsec->relocs[reloc_idx];

if (memcmp(reloc, &empty, sizeof(empty))) {
WARN("%s: %s: reloc %d already initialized!",
@@ -841,7 +840,6 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
return NULL;

list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &rsec->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));

return reloc;
@@ -944,14 +942,13 @@ static int read_relocs(struct elf *elf)
rsec->base->rsec = rsec;

nr_reloc = 0;
- rsec->reloc_data = calloc(rsec->sh.sh_size / rsec->sh.sh_entsize,
- sizeof(*reloc));
- if (!rsec->reloc_data) {
+ rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc));
+ if (!rsec->relocs) {
perror("calloc");
return -1;
}
- for (i = 0; i < rsec->sh.sh_size / rsec->sh.sh_entsize; i++) {
- reloc = &rsec->reloc_data[i];
+ for (i = 0; i < sec_num_entries(rsec); i++) {
+ reloc = &rsec->relocs[i];

if (read_reloc(rsec, i, reloc))
return -1;
@@ -967,7 +964,6 @@ static int read_relocs(struct elf *elf)
}

list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &rsec->reloc_list);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));

nr_reloc++;
@@ -1093,7 +1089,6 @@ struct section *elf_create_section(struct elf *elf, const char *name,
memset(sec, 0, sizeof(*sec));

INIT_LIST_HEAD(&sec->symbol_list);
- INIT_LIST_HEAD(&sec->reloc_list);

s = elf_newscn(elf->elf);
if (!s) {
@@ -1186,9 +1181,8 @@ static struct section *elf_create_rela_section(struct elf *elf,
rsec->sh.sh_info = sec->idx;
rsec->sh.sh_flags = SHF_INFO_LINK;

- rsec->reloc_data = calloc(rsec->sh.sh_size / rsec->sh.sh_entsize,
- sizeof(struct reloc));
- if (!rsec->reloc_data) {
+ rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
+ if (!rsec->relocs) {
perror("calloc");
return NULL;
}
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index a938cb1..a09da20 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -33,14 +33,13 @@ struct section {
GElf_Shdr sh;
struct rb_root_cached symbol_tree;
struct list_head symbol_list;
- struct list_head reloc_list;
struct section *base, *rsec;
struct symbol *sym;
Elf_Data *data;
char *name;
int idx;
bool _changed, text, rodata, noinstr, init, truncate;
- struct reloc *reloc_data;
+ struct reloc *relocs;
};

struct symbol {
@@ -68,7 +67,6 @@ struct symbol {
};

struct reloc {
- struct list_head list;
struct hlist_node hash;
union {
GElf_Rela rela;
@@ -197,6 +195,11 @@ static inline void mark_sec_changed(struct elf *elf, struct section *sec,
elf->changed |= changed;
}

+static inline unsigned int sec_num_entries(struct section *sec)
+{
+ return sec->sh.sh_size / sec->sh.sh_entsize;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

@@ -210,10 +213,15 @@ static inline void mark_sec_changed(struct elf *elf, struct section *sec,
sec_for_each_sym(__sec, sym)

#define for_each_reloc(rsec, reloc) \
- list_for_each_entry(reloc, &rsec->reloc_list, list)
+ for (int __i = 0, __fake = 1; __fake; __fake = 0) \
+ for (reloc = rsec->relocs; \
+ __i < sec_num_entries(rsec); \
+ __i++, reloc++)

#define for_each_reloc_from(rsec, reloc) \
- list_for_each_entry_from(reloc, &rsec->reloc_list, list)
+ for (int __i = reloc->idx; \
+ __i < sec_num_entries(rsec); \
+ __i++, reloc++)

#define OFFSET_STRIDE_BITS 4
#define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)

Subject: [tip: objtool/core] objtool: Get rid of reloc->addend

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

Commit-ID: 0696b6e314dbe4bd2f24d5e749469f57ea095a9f
Gitweb: https://git.kernel.org/tip/0696b6e314dbe4bd2f24d5e749469f57ea095a9f
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:21:08 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:23 -07:00

objtool: Get rid of reloc->addend

Get the addend from the embedded GElf_Rel[a] struct.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 42.10G
- After: peak heap memory consumption: 40.37G

Link: https://lore.kernel.org/r/ad2354f95d9ddd86094e3f7687acfa0750657784.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/arch/x86/decode.c | 4 +-
tools/objtool/arch/x86/special.c | 2 +-
tools/objtool/check.c | 69 ++++++++++++++++------------
tools/objtool/elf.c | 10 +---
tools/objtool/include/objtool/elf.h | 6 +-
tools/objtool/special.c | 4 +-
6 files changed, 53 insertions(+), 42 deletions(-)

diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index ffb12e8..2e1caab 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -623,11 +623,11 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
if (!immr || strcmp(immr->sym->name, "pv_ops"))
break;

- idx = (immr->addend + 8) / sizeof(void *);
+ idx = (reloc_addend(immr) + 8) / sizeof(void *);

func = disp->sym;
if (disp->sym->type == STT_SECTION)
- func = find_symbol_by_offset(disp->sym->sec, disp->addend);
+ func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
if (!func) {
WARN("no func for pv_ops[]");
return -1;
diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/special.c
index 1a54a24..65f48f3 100644
--- a/tools/objtool/arch/x86/special.c
+++ b/tools/objtool/arch/x86/special.c
@@ -105,7 +105,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
!text_reloc->sym->sec->rodata)
return NULL;

- table_offset = text_reloc->addend;
+ table_offset = reloc_addend(text_reloc);
table_sec = text_reloc->sym->sec;

if (reloc_type(text_reloc) == R_X86_64_PC32)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 04b4152..745487d 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -509,7 +509,8 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)

func = reloc->sym;
if (func->type == STT_SECTION)
- func = find_symbol_by_offset(reloc->sym->sec, reloc->addend);
+ func = find_symbol_by_offset(reloc->sym->sec,
+ reloc_addend(reloc));

idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long);

@@ -583,6 +584,7 @@ static int add_dead_ends(struct objtool_file *file)
struct section *rsec;
struct reloc *reloc;
struct instruction *insn;
+ s64 addend;

/*
* Check for manually annotated dead ends.
@@ -592,23 +594,27 @@ static int add_dead_ends(struct objtool_file *file)
goto reachable;

for_each_reloc(rsec, reloc) {
+
if (reloc->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in %s", rsec->name);
return -1;
}
- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+
+ addend = reloc_addend(reloc);
+
+ insn = find_insn(file, reloc->sym->sec, addend);
if (insn)
insn = prev_insn_same_sec(file, insn);
- else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+ else if (addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}
} else {
WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}

@@ -627,23 +633,27 @@ reachable:
return 0;

for_each_reloc(rsec, reloc) {
+
if (reloc->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in %s", rsec->name);
return -1;
}
- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+
+ addend = reloc_addend(reloc);
+
+ insn = find_insn(file, reloc->sym->sec, addend);
if (insn)
insn = prev_insn_same_sec(file, insn);
- else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+ else if (addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}
} else {
WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, reloc->addend);
+ reloc->sym->sec->name, addend);
return -1;
}

@@ -1026,7 +1036,7 @@ static void add_ignores(struct objtool_file *file)
break;

case STT_SECTION:
- func = find_func_by_offset(reloc->sym->sec, reloc->addend);
+ func = find_func_by_offset(reloc->sym->sec, reloc_addend(reloc));
if (!func)
continue;
break;
@@ -1266,7 +1276,7 @@ static int add_ignore_alternatives(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.ignore_alts entry");
return -1;
@@ -1542,7 +1552,7 @@ static int add_jump_destinations(struct objtool_file *file)
dest_off = arch_jump_destination(insn);
} else if (reloc->sym->type == STT_SECTION) {
dest_sec = reloc->sym->sec;
- dest_off = arch_dest_reloc_offset(reloc->addend);
+ dest_off = arch_dest_reloc_offset(reloc_addend(reloc));
} else if (reloc->sym->retpoline_thunk) {
add_retpoline_call(file, insn);
continue;
@@ -1559,7 +1569,7 @@ static int add_jump_destinations(struct objtool_file *file)
} else if (reloc->sym->sec->idx) {
dest_sec = reloc->sym->sec;
dest_off = reloc->sym->sym.st_value +
- arch_dest_reloc_offset(reloc->addend);
+ arch_dest_reloc_offset(reloc_addend(reloc));
} else {
/* non-func asm code jumping to another file */
continue;
@@ -1676,7 +1686,7 @@ static int add_call_destinations(struct objtool_file *file)
}

} else if (reloc->sym->type == STT_SECTION) {
- dest_off = arch_dest_reloc_offset(reloc->addend);
+ dest_off = arch_dest_reloc_offset(reloc_addend(reloc));
dest = find_call_destination(reloc->sym->sec, dest_off);
if (!dest) {
WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx",
@@ -2003,10 +2013,10 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,

/* Detect function pointers from contiguous objects: */
if (reloc->sym->sec == pfunc->sec &&
- reloc->addend == pfunc->offset)
+ reloc_addend(reloc) == pfunc->offset)
break;

- dest_insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ dest_insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!dest_insn)
break;

@@ -2067,7 +2077,7 @@ static struct reloc *find_jump_table(struct objtool_file *file,
table_reloc = arch_find_switch_table(file, insn);
if (!table_reloc)
continue;
- dest_insn = find_insn(file, table_reloc->sym->sec, table_reloc->addend);
+ dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;

@@ -2203,7 +2213,7 @@ static int read_unwind_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("can't find insn for unwind_hints[%d]", i);
return -1;
@@ -2271,7 +2281,8 @@ static int read_noendbr_hints(struct objtool_file *file)
return 0;

for_each_reloc(rsec, reloc) {
- insn = find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc->addend);
+ insn = find_insn(file, reloc->sym->sec,
+ reloc->sym->offset + reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.noendbr entry");
return -1;
@@ -2299,7 +2310,7 @@ static int read_retpoline_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.retpoline_safe entry");
return -1;
@@ -2335,7 +2346,7 @@ static int read_instr_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_end entry");
return -1;
@@ -2354,7 +2365,7 @@ static int read_instr_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_begin entry");
return -1;
@@ -2382,7 +2393,7 @@ static int read_validate_unret_hints(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.instr_end entry");
return -1;
@@ -2413,7 +2424,7 @@ static int read_intra_function_calls(struct objtool_file *file)
return -1;
}

- insn = find_insn(file, reloc->sym->sec, reloc->addend);
+ insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
if (!insn) {
WARN("bad .discard.intra_function_call entry");
return -1;
@@ -3317,7 +3328,7 @@ static inline const char *call_dest_name(struct instruction *insn)

reloc = insn_reloc(NULL, insn);
if (reloc && !strcmp(reloc->sym->name, "pv_ops")) {
- idx = (reloc->addend / sizeof(void *));
+ idx = (reloc_addend(reloc) / sizeof(void *));
snprintf(pvname, sizeof(pvname), "pv_ops[%d]", idx);
return pvname;
}
@@ -3335,7 +3346,7 @@ static bool pv_call_dest(struct objtool_file *file, struct instruction *insn)
if (!reloc || strcmp(reloc->sym->name, "pv_ops"))
return false;

- idx = (arch_dest_reloc_offset(reloc->addend) / sizeof(void *));
+ idx = (arch_dest_reloc_offset(reloc_addend(reloc)) / sizeof(void *));

if (file->pv_ops[idx].clean)
return true;
@@ -4279,9 +4290,9 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
off = reloc->sym->offset;
if (reloc_type(reloc) == R_X86_64_PC32 ||
reloc_type(reloc) == R_X86_64_PLT32)
- off += arch_dest_reloc_offset(reloc->addend);
+ off += arch_dest_reloc_offset(reloc_addend(reloc));
else
- off += reloc->addend;
+ off += reloc_addend(reloc);

dest = find_insn(file, reloc->sym->sec, off);
if (!dest)
@@ -4338,7 +4349,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file,
struct instruction *dest;

dest = find_insn(file, reloc->sym->sec,
- reloc->sym->offset + reloc->addend);
+ reloc->sym->offset + reloc_addend(reloc));
if (!dest)
return 0;

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index be9d24d..16e019a 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -833,10 +833,10 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,

reloc->sec = rsec;
reloc->sym = sym;
- reloc->addend = addend;

reloc->rel.r_offset = offset;
reloc->rel.r_info = GELF_R_INFO(sym->idx, type);
+ reloc->rela.r_addend = addend;

if (elf_write_reloc(elf, reloc))
return NULL;
@@ -911,8 +911,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
return -1;
}

- reloc->addend = rela ? reloc->rela.r_addend : 0;
-
return 0;
}

@@ -1231,12 +1229,10 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc)
struct section *rsec = reloc->sec;
int ret;

- if (rsec->sh.sh_type == SHT_RELA) {
- reloc->rela.r_addend = reloc->addend;
+ if (rsec->sh.sh_type == SHT_RELA)
ret = gelf_update_rela(rsec->data, reloc_idx(reloc), &reloc->rela);
- } else {
+ else
ret = gelf_update_rel(rsec->data, reloc_idx(reloc), &reloc->rel);
- }

if (!ret) {
WARN_ELF("gelf_update_rela");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 41d2149..be08b32 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -75,7 +75,6 @@ struct reloc {
struct section *sec;
struct symbol *sym;
struct list_head sym_reloc_entry;
- s64 addend;
bool jump_table_start;
};

@@ -217,6 +216,11 @@ static inline void set_reloc_type(struct reloc *reloc, int type)
reloc->rel.r_info = GELF_R_INFO(GELF_R_SYM(reloc->rel.r_info), type);
}

+static inline s64 reloc_addend(struct reloc *reloc)
+{
+ return reloc->rela.r_addend;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index baa85c3..91b1950 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -62,7 +62,7 @@ static void reloc_to_sec_off(struct reloc *reloc, struct section **sec,
unsigned long *off)
{
*sec = reloc->sym->sec;
- *off = reloc->sym->offset + reloc->addend;
+ *off = reloc->sym->offset + reloc_addend(reloc);
}

static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
@@ -126,7 +126,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
sec, offset + entry->key);
return -1;
}
- alt->key_addend = key_reloc->addend;
+ alt->key_addend = reloc_addend(key_reloc);
}

return 0;

Subject: [tip: objtool/core] objtool: Free insns when done

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

Commit-ID: d93b5935fd47007597aed5105a902a10204bc30e
Gitweb: https://git.kernel.org/tip/d93b5935fd47007597aed5105a902a10204bc30e
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:21:13 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:27 -07:00

objtool: Free insns when done

Free the decoded instructions as they're no longer needed after this
point. This frees up a big chunk of heap, which will come handy when
skipping the reading of DWARF section data.

Link: https://lore.kernel.org/r/4d4bca1a0f869de020dac80d91f9acbf6df77eab.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/check.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 47ff130..8936a05 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4596,6 +4596,34 @@ static int disas_warned_funcs(struct objtool_file *file)
return 0;
}

+struct insn_chunk {
+ void *addr;
+ struct insn_chunk *next;
+};
+
+/*
+ * Reduce peak RSS usage by freeing insns memory before writing the ELF file,
+ * which can trigger more allocations for .debug_* sections whose data hasn't
+ * been read yet.
+ */
+static void free_insns(struct objtool_file *file)
+{
+ struct instruction *insn;
+ struct insn_chunk *chunks = NULL, *chunk;
+
+ for_each_insn(file, insn) {
+ if (!insn->idx) {
+ chunk = malloc(sizeof(*chunk));
+ chunk->addr = insn;
+ chunk->next = chunks;
+ chunks = chunk;
+ }
+ }
+
+ for (chunk = chunks; chunk; chunk = chunk->next)
+ free(chunk->addr);
+}
+
int check(struct objtool_file *file)
{
int ret, warnings = 0;
@@ -4742,6 +4770,8 @@ int check(struct objtool_file *file)
warnings += ret;
}

+ free_insns(file);
+
if (opts.verbose)
disas_warned_funcs(file);


Subject: [tip: objtool/core] objtool: Add elf_create_section_pair()

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

Commit-ID: 6342a20efbd8b70d169c325b2c27a8a8f96388d5
Gitweb: https://git.kernel.org/tip/6342a20efbd8b70d169c325b2c27a8a8f96388d5
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:20:59 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:17 -07:00

objtool: Add elf_create_section_pair()

When creating an annotation section, allocate the reloc section data at
the beginning. This simplifies the data model a bit and also saves
memory due to the removal of malloc() in elf_rebuild_reloc_section().

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 53.49G
- After: peak heap memory consumption: 49.02G

Link: https://lore.kernel.org/r/048e908f3ede9b66c15e44672b6dda992b1dae3e.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/arch/powerpc/include/arch/elf.h | 11 +-
tools/objtool/arch/x86/include/arch/elf.h | 11 +-
tools/objtool/check.c | 129 +++++----------
tools/objtool/elf.c | 151 ++++++++++-------
tools/objtool/include/objtool/elf.h | 33 +++-
tools/objtool/orc_gen.c | 6 +-
6 files changed, 184 insertions(+), 157 deletions(-)

diff --git a/tools/objtool/arch/powerpc/include/arch/elf.h b/tools/objtool/arch/powerpc/include/arch/elf.h
index 73f9ae1..66814fa 100644
--- a/tools/objtool/arch/powerpc/include/arch/elf.h
+++ b/tools/objtool/arch/powerpc/include/arch/elf.h
@@ -1,10 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-
#ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF

-#define R_NONE R_PPC_NONE
-#define R_ABS64 R_PPC64_ADDR64
-#define R_ABS32 R_PPC_ADDR32
+#define R_NONE R_PPC_NONE
+#define R_ABS64 R_PPC64_ADDR64
+#define R_ABS32 R_PPC_ADDR32
+#define R_DATA32 R_PPC_REL32
+#define R_DATA64 R_PPC64_REL64
+#define R_TEXT32 R_PPC_REL32
+#define R_TEXT64 R_PPC64_REL32

#endif /* _OBJTOOL_ARCH_ELF */
diff --git a/tools/objtool/arch/x86/include/arch/elf.h b/tools/objtool/arch/x86/include/arch/elf.h
index ac14987..7131f7f 100644
--- a/tools/objtool/arch/x86/include/arch/elf.h
+++ b/tools/objtool/arch/x86/include/arch/elf.h
@@ -1,8 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _OBJTOOL_ARCH_ELF
#define _OBJTOOL_ARCH_ELF

-#define R_NONE R_X86_64_NONE
-#define R_ABS64 R_X86_64_64
-#define R_ABS32 R_X86_64_32
+#define R_NONE R_X86_64_NONE
+#define R_ABS32 R_X86_64_32
+#define R_ABS64 R_X86_64_64
+#define R_DATA32 R_X86_64_PC32
+#define R_DATA64 R_X86_64_PC32
+#define R_TEXT32 R_X86_64_PC32
+#define R_TEXT64 R_X86_64_PC32

#endif /* _OBJTOOL_ARCH_ELF */
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 2ab8699..3bc97c2 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -8,7 +8,6 @@
#include <inttypes.h>
#include <sys/mman.h>

-#include <arch/elf.h>
#include <objtool/builtin.h>
#include <objtool/cfi.h>
#include <objtool/arch.h>
@@ -656,8 +655,8 @@ reachable:

static int create_static_call_sections(struct objtool_file *file)
{
- struct section *sec;
struct static_call_site *site;
+ struct section *sec;
struct instruction *insn;
struct symbol *key_sym;
char *key_name, *tmp;
@@ -677,25 +676,21 @@ static int create_static_call_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->static_call_list, call_node)
idx++;

- sec = elf_create_section(file->elf, ".static_call_sites",
- sizeof(struct static_call_site), idx);
+ sec = elf_create_section_pair(file->elf, ".static_call_sites",
+ sizeof(*site), idx, idx * 2);
if (!sec)
return -1;

- /* Allow modules to set the low bits of static_call_site::key */
+ /* Allow modules to modify the low bits of static_call_site::key */
sec->sh.sh_flags |= SHF_WRITE;

idx = 0;
list_for_each_entry(insn, &file->static_call_list, call_node) {

- site = (struct static_call_site *)sec->data->d_buf + idx;
- memset(site, 0, sizeof(struct static_call_site));
-
/* populate reloc for 'addr' */
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(struct static_call_site),
- R_X86_64_PC32,
- insn->sec, insn->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(*site), idx * 2,
+ insn->sec, insn->offset))
return -1;

/* find key symbol */
@@ -735,10 +730,10 @@ static int create_static_call_sections(struct objtool_file *file)
free(key_name);

/* populate reloc for 'key' */
- if (elf_add_reloc(file->elf, sec,
- idx * sizeof(struct static_call_site) + 4,
- R_X86_64_PC32, key_sym,
- is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
+ if (!elf_init_reloc_data_sym(file->elf, sec,
+ idx * sizeof(*site) + 4,
+ (idx * 2) + 1, key_sym,
+ is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
return -1;

idx++;
@@ -766,26 +761,18 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".retpoline_sites",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .retpoline_sites");
+ sec = elf_create_section_pair(file->elf, ".retpoline_sites",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {

- int *site = (int *)sec->data->d_buf + idx;
- *site = 0;
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .retpoline_sites");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -812,26 +799,18 @@ static int create_return_sites_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".return_sites",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .return_sites");
+ sec = elf_create_section_pair(file->elf, ".return_sites",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->return_thunk_list, call_node) {

- int *site = (int *)sec->data->d_buf + idx;
- *site = 0;
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .return_sites");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -864,12 +843,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
if (!idx)
return 0;

- sec = elf_create_section(file->elf, ".ibt_endbr_seal",
- sizeof(int), idx);
- if (!sec) {
- WARN("elf_create_section: .ibt_endbr_seal");
+ sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal",
+ sizeof(int), idx, idx);
+ if (!sec)
return -1;
- }

idx = 0;
list_for_each_entry(insn, &file->endbr_list, call_node) {
@@ -884,13 +861,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
!strcmp(sym->name, "cleanup_module")))
WARN("%s(): not an indirect call target", sym->name);

- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(int),
- R_X86_64_PC32,
- insn->sec, insn->offset)) {
- WARN("elf_add_reloc_to_insn: .ibt_endbr_seal");
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(int), idx,
+ insn->sec, insn->offset))
return -1;
- }

idx++;
}
@@ -902,7 +876,6 @@ static int create_cfi_sections(struct objtool_file *file)
{
struct section *sec;
struct symbol *sym;
- unsigned int *loc;
int idx;

sec = find_section_by_name(file->elf, ".cfi_sites");
@@ -923,7 +896,8 @@ static int create_cfi_sections(struct objtool_file *file)
idx++;
}

- sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx);
+ sec = elf_create_section_pair(file->elf, ".cfi_sites",
+ sizeof(unsigned int), idx, idx);
if (!sec)
return -1;

@@ -935,13 +909,9 @@ static int create_cfi_sections(struct objtool_file *file)
if (strncmp(sym->name, "__cfi_", 6))
continue;

- loc = (unsigned int *)sec->data->d_buf + idx;
- memset(loc, 0, sizeof(unsigned int));
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(unsigned int),
- R_X86_64_PC32,
- sym->sec, sym->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(unsigned int), idx,
+ sym->sec, sym->offset))
return -1;

idx++;
@@ -971,7 +941,8 @@ static int create_mcount_loc_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
idx++;

- sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
+ sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size,
+ idx, idx);
if (!sec)
return -1;

@@ -979,17 +950,17 @@ static int create_mcount_loc_sections(struct objtool_file *file)

idx = 0;
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
- void *loc;

- loc = sec->data->d_buf + idx;
- memset(loc, 0, addr_size);
+ struct reloc *reloc;

- if (elf_add_reloc_to_insn(file->elf, sec, idx,
- addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
- insn->sec, insn->offset))
+ reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx,
+ insn->sec, insn->offset);
+ if (!reloc)
return -1;

- idx += addr_size;
+ reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32;
+
+ idx++;
}

return 0;
@@ -999,7 +970,6 @@ static int create_direct_call_sections(struct objtool_file *file)
{
struct instruction *insn;
struct section *sec;
- unsigned int *loc;
int idx;

sec = find_section_by_name(file->elf, ".call_sites");
@@ -1016,20 +986,17 @@ static int create_direct_call_sections(struct objtool_file *file)
list_for_each_entry(insn, &file->call_list, call_node)
idx++;

- sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx);
+ sec = elf_create_section_pair(file->elf, ".call_sites",
+ sizeof(unsigned int), idx, idx);
if (!sec)
return -1;

idx = 0;
list_for_each_entry(insn, &file->call_list, call_node) {

- loc = (unsigned int *)sec->data->d_buf + idx;
- memset(loc, 0, sizeof(unsigned int));
-
- if (elf_add_reloc_to_insn(file->elf, sec,
- idx * sizeof(unsigned int),
- R_X86_64_PC32,
- insn->sec, insn->offset))
+ if (!elf_init_reloc_text_sym(file->elf, sec,
+ idx * sizeof(unsigned int), idx,
+ insn->sec, insn->offset))
return -1;

idx++;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 67967c2..5cbc9d5 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -533,41 +533,6 @@ err:
return -1;
}

-static struct section *elf_create_rela_section(struct elf *elf,
- struct section *sec);
-
-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
- unsigned int type, struct symbol *sym, s64 addend)
-{
- struct reloc *reloc;
-
- if (!sec->rsec && !elf_create_rela_section(elf, sec))
- return -1;
-
- reloc = malloc(sizeof(*reloc));
- if (!reloc) {
- perror("malloc");
- return -1;
- }
- memset(reloc, 0, sizeof(*reloc));
-
- reloc->sec = sec->rsec;
- reloc->offset = offset;
- reloc->type = type;
- reloc->sym = sym;
- reloc->addend = addend;
-
- list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
- list_add_tail(&reloc->list, &sec->rsec->reloc_list);
- elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
-
- sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize;
-
- mark_sec_changed(elf, sec->rsec, true);
-
- return 0;
-}
-
/*
* Ensure that any reloc section containing references to @sym is marked
* changed such that it will get re-generated in elf_rebuild_reloc_sections()
@@ -841,13 +806,57 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
return sym;
}

-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
- unsigned long offset, unsigned int type,
- struct section *insn_sec, unsigned long insn_off)
+static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
+ unsigned int reloc_idx,
+ unsigned long offset, struct symbol *sym,
+ s64 addend, unsigned int type)
+{
+ struct reloc *reloc;
+
+ if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
+ WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
+ __func__, reloc_idx, rsec->name, rsec->sh.sh_size);
+ return NULL;
+ }
+
+ reloc = malloc(sizeof(*reloc));
+ if (!reloc) {
+ perror("malloc");
+ return NULL;
+ }
+ memset(reloc, 0, sizeof(*reloc));
+
+ reloc->idx = reloc_idx;
+ reloc->sec = rsec;
+ reloc->offset = offset;
+ reloc->type = type;
+ reloc->sym = sym;
+ reloc->addend = addend;
+
+ list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
+ list_add_tail(&reloc->list, &rsec->reloc_list);
+ elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
+
+ mark_sec_changed(elf, rsec, true);
+
+ return reloc;
+}
+
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct section *insn_sec,
+ unsigned long insn_off)
{
struct symbol *sym = insn_sec->sym;
int addend = insn_off;

+ if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
+ WARN("bad call to %s() for data symbol %s",
+ __func__, sym->name);
+ return NULL;
+ }
+
if (!sym) {
/*
* Due to how weak functions work, we must use section based
@@ -857,12 +866,29 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
*/
sym = elf_create_section_symbol(elf, insn_sec);
if (!sym)
- return -1;
+ return NULL;

insn_sec->sym = sym;
}

- return elf_add_reloc(elf, sec, offset, type, sym, addend);
+ return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+ elf_text_rela_type(elf));
+}
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct symbol *sym,
+ s64 addend)
+{
+ if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
+ WARN("bad call to %s() for text symbol %s",
+ __func__, sym->name);
+ return NULL;
+ }
+
+ return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
+ elf_data_rela_type(elf));
}

static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
@@ -1048,7 +1074,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
}

struct section *elf_create_section(struct elf *elf, const char *name,
- size_t entsize, int nr)
+ size_t entsize, unsigned int nr)
{
struct section *sec, *shstrtab;
size_t size = entsize * nr;
@@ -1129,7 +1155,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
}

static struct section *elf_create_rela_section(struct elf *elf,
- struct section *sec)
+ struct section *sec,
+ unsigned int reloc_nr)
{
struct section *rsec;
char *rsec_name;
@@ -1142,46 +1169,50 @@ 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), 0);
+ rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
free(rsec_name);
if (!rsec)
return NULL;

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

+ sec->rsec = rsec;
+ rsec->base = sec;
+
return rsec;
}

+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr,
+ unsigned int reloc_nr)
+{
+ struct section *sec;
+
+ sec = elf_create_section(elf, name, entsize, nr);
+ if (!sec)
+ return NULL;
+
+ if (!elf_create_rela_section(elf, sec, reloc_nr))
+ return NULL;
+
+ return sec;
+}
+
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
{
- bool rela = rsec->sh.sh_type == SHT_RELA;
struct reloc *reloc;
int idx = 0, ret;
- void *buf;
-
- /* Allocate a buffer for relocations */
- buf = malloc(rsec->sh.sh_size);
- if (!buf) {
- perror("malloc");
- return -1;
- }
-
- rsec->data->d_buf = buf;
- rsec->data->d_size = rsec->sh.sh_size;
- rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;

idx = 0;
list_for_each_entry(reloc, &rsec->reloc_list, list) {
reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
- if (rela) {
+ if (rsec->sh.sh_type == SHT_RELA) {
reloc->rela.r_addend = reloc->addend;
ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
} else {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 56b66ff..74f6393 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -111,15 +111,26 @@ 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, int nr);
+
+struct section *elf_create_section(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr);
+struct section *elf_create_section_pair(struct elf *elf, const char *name,
+ size_t entsize, unsigned int nr,
+ unsigned int reloc_nr);

struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);

-int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
- unsigned int type, struct symbol *sym, s64 addend);
-int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
- unsigned long offset, unsigned int type,
- struct section *insn_sec, unsigned long insn_off);
+struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct section *insn_sec,
+ unsigned long insn_off);
+
+struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
+ unsigned long offset,
+ unsigned int reloc_idx,
+ struct symbol *sym,
+ s64 addend);

int elf_write_insn(struct elf *elf, struct section *sec,
unsigned long offset, unsigned int len,
@@ -159,6 +170,16 @@ static inline size_t elf_rela_size(struct elf *elf)
return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
}

+static inline unsigned int elf_data_rela_type(struct elf *elf)
+{
+ return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
+}
+
+static inline unsigned int elf_text_rela_type(struct elf *elf)
+{
+ return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
+}
+
static inline bool is_reloc_sec(struct section *sec)
{
return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c
index d5f750b..bae3439 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/orc_gen.c
@@ -118,8 +118,8 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec,
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);

/* populate reloc for ip */
- if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32,
- insn_sec, insn_off))
+ if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
+ insn_sec, insn_off))
return -1;

return 0;
@@ -242,7 +242,7 @@ int orc_create(struct objtool_file *file)
if (!orc_sec)
return -1;

- sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr);
+ sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);
if (!sec)
return -1;


Subject: [tip: objtool/core] objtool: Shrink elf hash nodes

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

Commit-ID: 02b54001066364aee72bc4c802b42a96c6e0dc1f
Gitweb: https://git.kernel.org/tip/02b54001066364aee72bc4c802b42a96c6e0dc1f
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:21:11 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:25 -07:00

objtool: Shrink elf hash nodes

Instead of using hlist for the 'struct elf' hashes, use a custom
single-linked list scheme.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 36.89G
- After: peak heap memory consumption: 35.12G

Link: https://lore.kernel.org/r/6e8cd305ed22e743c30d6e72cfdc1be20fb94cd4.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/elf.c | 52 +++++++++++++++++++++++-----
tools/objtool/include/objtool/elf.h | 24 +++++++------
2 files changed, 58 insertions(+), 18 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 4b0de0e..04038b1 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -32,16 +32,52 @@ static inline u32 str_hash(const char *str)
#define __elf_table(name) (elf->name##_hash)
#define __elf_bits(name) (elf->name##_bits)

-#define elf_hash_add(name, node, key) \
- hlist_add_head(node, &__elf_table(name)[hash_min(key, __elf_bits(name))])
+#define __elf_table_entry(name, key) \
+ __elf_table(name)[hash_min(key, __elf_bits(name))]
+
+#define elf_hash_add(name, node, key) \
+({ \
+ struct elf_hash_node *__node = node; \
+ __node->next = __elf_table_entry(name, key); \
+ __elf_table_entry(name, key) = __node; \
+})
+
+static inline void __elf_hash_del(struct elf_hash_node *node,
+ struct elf_hash_node **head)
+{
+ struct elf_hash_node *cur, *prev;

-#define elf_hash_for_each_possible(name, obj, member, key) \
- hlist_for_each_entry(obj, &__elf_table(name)[hash_min(key, __elf_bits(name))], member)
+ if (node == *head) {
+ *head = node->next;
+ return;
+ }
+
+ for (prev = NULL, cur = *head; cur; prev = cur, cur = cur->next) {
+ if (cur == node) {
+ prev->next = cur->next;
+ break;
+ }
+ }
+}
+
+#define elf_hash_del(name, node, key) \
+ __elf_hash_del(node, &__elf_table_entry(name, key))
+
+#define elf_list_entry(ptr, type, member) \
+({ \
+ typeof(ptr) __ptr = (ptr); \
+ __ptr ? container_of(__ptr, type, member) : NULL; \
+})
+
+#define elf_hash_for_each_possible(name, obj, member, key) \
+ for (obj = elf_list_entry(__elf_table_entry(name, key), typeof(*obj), member); \
+ obj; \
+ obj = elf_list_entry(obj->member.next, typeof(*(obj)), member))

#define elf_alloc_hash(name, size) \
({ \
__elf_bits(name) = max(10, ilog2(size)); \
- __elf_table(name) = mmap(NULL, sizeof(struct hlist_head) << __elf_bits(name), \
+ __elf_table(name) = mmap(NULL, sizeof(struct elf_hash_node *) << __elf_bits(name), \
PROT_READ|PROT_WRITE, \
MAP_PRIVATE|MAP_ANON, -1, 0); \
if (__elf_table(name) == (void *)-1L) { \
@@ -713,10 +749,10 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
first_non_local = symtab->sh.sh_info;
old = find_symbol_by_index(elf, first_non_local);
if (old) {
- old->idx = new_idx;

- hlist_del(&old->hash);
- elf_hash_add(symbol, &old->hash, old->idx);
+ elf_hash_del(symbol, &old->hash, old->idx);
+ elf_hash_add(symbol, &old->hash, new_idx);
+ old->idx = new_idx;

if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
WARN("elf_update_symbol move");
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 7b808ac..03a9040 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -26,10 +26,14 @@
#define ELF_C_READ_MMAP ELF_C_READ
#endif

+struct elf_hash_node {
+ struct elf_hash_node *next;
+};
+
struct section {
struct list_head list;
- struct hlist_node hash;
- struct hlist_node name_hash;
+ struct elf_hash_node hash;
+ struct elf_hash_node name_hash;
GElf_Shdr sh;
struct rb_root_cached symbol_tree;
struct list_head symbol_list;
@@ -45,8 +49,8 @@ struct section {
struct symbol {
struct list_head list;
struct rb_node node;
- struct hlist_node hash;
- struct hlist_node name_hash;
+ struct elf_hash_node hash;
+ struct elf_hash_node name_hash;
GElf_Sym sym;
struct section *sec;
char *name;
@@ -67,7 +71,7 @@ struct symbol {
};

struct reloc {
- struct hlist_node hash;
+ struct elf_hash_node hash;
union {
GElf_Rela rela;
GElf_Rel rel;
@@ -93,11 +97,11 @@ struct elf {
int section_name_bits;
int reloc_bits;

- struct hlist_head *symbol_hash;
- struct hlist_head *symbol_name_hash;
- struct hlist_head *section_hash;
- struct hlist_head *section_name_hash;
- struct hlist_head *reloc_hash;
+ struct elf_hash_node **symbol_hash;
+ struct elf_hash_node **symbol_name_hash;
+ struct elf_hash_node **section_hash;
+ struct elf_hash_node **section_name_hash;
+ struct elf_hash_node **reloc_hash;

struct section *section_data;
struct symbol *symbol_data;

Subject: [tip: objtool/core] objtool: Get rid of reloc->offset

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

Commit-ID: e4cbb9b81f1f7519c7ae3abda09cb15794022952
Gitweb: https://git.kernel.org/tip/e4cbb9b81f1f7519c7ae3abda09cb15794022952
Author: Josh Poimboeuf <[email protected]>
AuthorDate: Tue, 30 May 2023 10:21:06 -07:00
Committer: Josh Poimboeuf <[email protected]>
CommitterDate: Wed, 07 Jun 2023 10:03:21 -07:00

objtool: Get rid of reloc->offset

Get the offset from the embedded GElf_Rel[a] struct.

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 43.83G
- After: peak heap memory consumption: 42.10G

Link: https://lore.kernel.org/r/2b9ec01178baa346a99522710bf2e82159412e3a.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <[email protected]>
---
tools/objtool/check.c | 14 +++++++-------
tools/objtool/elf.c | 10 +++++-----
tools/objtool/include/objtool/elf.h | 8 ++++++--
3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e21138d..e06ffad 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -511,11 +511,11 @@ static int add_pv_ops(struct objtool_file *file, const char *symname)
if (func->type == STT_SECTION)
func = find_symbol_by_offset(reloc->sym->sec, reloc->addend);

- idx = (reloc->offset - sym->offset) / sizeof(unsigned long);
+ idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long);

objtool_pv_add(file, idx, func);

- off = reloc->offset + 1;
+ off = reloc_offset(reloc) + 1;
if (off > end)
break;
}
@@ -1998,7 +1998,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
break;

/* Make sure the table entries are consecutive: */
- if (prev_offset && reloc->offset != prev_offset + 8)
+ if (prev_offset && reloc_offset(reloc) != prev_offset + 8)
break;

/* Detect function pointers from contiguous objects: */
@@ -2023,7 +2023,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
alt->insn = dest_insn;
alt->next = insn->alts;
insn->alts = alt;
- prev_offset = reloc->offset;
+ prev_offset = reloc_offset(reloc);
}

if (!prev_offset) {
@@ -4266,8 +4266,8 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn
for (reloc = insn_reloc(file, insn);
reloc;
reloc = find_reloc_by_dest_range(file->elf, insn->sec,
- reloc->offset + 1,
- (insn->offset + insn->len) - (reloc->offset + 1))) {
+ reloc_offset(reloc) + 1,
+ (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) {

/*
* static_call_update() references the trampoline, which
@@ -4350,7 +4350,7 @@ static int validate_ibt_data_reloc(struct objtool_file *file,
return 0;

WARN_FUNC("data relocation to !ENDBR: %s",
- reloc->sec->base, reloc->offset,
+ reloc->sec->base, reloc_offset(reloc),
offstr(dest->sec, dest->offset));

return 1;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 70c8012..2b45460 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -246,8 +246,9 @@ struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *se
if (reloc->sec != rsec)
continue;

- if (reloc->offset >= offset && reloc->offset < offset + len) {
- if (!r || reloc->offset < r->offset)
+ if (reloc_offset(reloc) >= offset &&
+ reloc_offset(reloc) < offset + len) {
+ if (!r || reloc_offset(reloc) < reloc_offset(r))
r = reloc;
}
}
@@ -830,11 +831,12 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
}

reloc->sec = rsec;
- reloc->offset = offset;
reloc->type = type;
reloc->sym = sym;
reloc->addend = addend;

+ reloc->rel.r_offset = offset;
+
if (elf_write_reloc(elf, reloc))
return NULL;

@@ -908,7 +910,6 @@ static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
return -1;
}

- reloc->offset = reloc->rel.r_offset;
reloc->type = GELF_R_TYPE(reloc->rel.r_info);
reloc->addend = rela ? reloc->rela.r_addend : 0;

@@ -1230,7 +1231,6 @@ int elf_write_reloc(struct elf *elf, struct reloc *reloc)
struct section *rsec = reloc->sec;
int ret;

- reloc->rel.r_offset = reloc->offset;
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);

if (rsec->sh.sh_type == SHT_RELA) {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 2a14da6..2070860 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -75,7 +75,6 @@ struct reloc {
struct section *sec;
struct symbol *sym;
struct list_head sym_reloc_entry;
- unsigned long offset;
s64 addend;
unsigned int type;
bool jump_table_start;
@@ -204,6 +203,11 @@ static inline unsigned int reloc_idx(struct reloc *reloc)
return reloc - reloc->sec->relocs;
}

+static inline unsigned long reloc_offset(struct reloc *reloc)
+{
+ return reloc->rel.r_offset;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)

@@ -253,7 +257,7 @@ static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)

static inline u32 reloc_hash(struct reloc *reloc)
{
- return sec_offset_hash(reloc->sec, reloc->offset);
+ return sec_offset_hash(reloc->sec, reloc_offset(reloc));
}

#endif /* _OBJTOOL_ELF_H */