* [PATCH 0/3] objtool: add support for >64k sections
@ 2020-04-21 18:07 Sami Tolvanen
2020-04-21 18:07 ` [PATCH 1/3] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
` (4 more replies)
0 siblings, 5 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 18:07 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra; +Cc: Kees Cook, linux-kernel, Sami Tolvanen
This series fixes objtool for binaries with >64k sections, and
includes optimizations to reduce the runtime for a binary with
~130k sections from >15 minutes to ~4 seconds.
Sami Tolvanen (3):
objtool: use gelf_getsymshndx to handle >64k sections
objtool: optimize insn_hash for split sections
objtool: optimize add_dead_ends for split sections
tools/objtool/check.c | 48 ++++++++++++++++++++++++++-----------------
tools/objtool/check.h | 9 ++++++++
tools/objtool/elf.c | 24 +++++++++++++++-------
tools/objtool/elf.h | 1 +
4 files changed, 56 insertions(+), 26 deletions(-)
base-commit: ae83d0b416db002fe95601e7f97f64b59514d936
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/3] objtool: use gelf_getsymshndx to handle >64k sections
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
@ 2020-04-21 18:07 ` Sami Tolvanen
2020-04-21 20:11 ` Kees Cook
2020-04-21 18:07 ` [PATCH 2/3] objtool: optimize insn_hash for split sections Sami Tolvanen
` (3 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 18:07 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra; +Cc: Kees Cook, linux-kernel, Sami Tolvanen
Currently, objtool fails to load the correct section for symbols when
the index is greater than SHN_LORESERVE. Use gelf_getsymshndx instead
of gelf_getsym to handle >64k sections.
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
tools/objtool/elf.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 09ddc8f1def3..887445e87380 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -327,12 +327,14 @@ static int read_sections(struct elf *elf)
static int read_symbols(struct elf *elf)
{
- struct section *symtab, *sec;
+ struct section *symtab, *symtab_shndx, *sec;
struct symbol *sym, *pfunc;
struct list_head *entry;
struct rb_node *pnode;
int symbols_nr, i;
char *coldstr;
+ Elf_Data *shndx_data = NULL;
+ Elf32_Word shndx;
symtab = find_section_by_name(elf, ".symtab");
if (!symtab) {
@@ -340,6 +342,10 @@ static int read_symbols(struct elf *elf)
return -1;
}
+ symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+ if (symtab_shndx)
+ shndx_data = symtab_shndx->data;
+
symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
for (i = 0; i < symbols_nr; i++) {
@@ -353,8 +359,9 @@ static int read_symbols(struct elf *elf)
sym->idx = i;
- if (!gelf_getsym(symtab->data, i, &sym->sym)) {
- WARN_ELF("gelf_getsym");
+ if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
+ &shndx)) {
+ WARN_ELF("gelf_getsymshndx");
goto err;
}
@@ -368,10 +375,13 @@ static int read_symbols(struct elf *elf)
sym->type = GELF_ST_TYPE(sym->sym.st_info);
sym->bind = GELF_ST_BIND(sym->sym.st_info);
- if (sym->sym.st_shndx > SHN_UNDEF &&
- sym->sym.st_shndx < SHN_LORESERVE) {
- sym->sec = find_section_by_index(elf,
- sym->sym.st_shndx);
+ if ((sym->sym.st_shndx > SHN_UNDEF &&
+ sym->sym.st_shndx < SHN_LORESERVE) ||
+ (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
+ if (sym->sym.st_shndx != SHN_XINDEX)
+ shndx = sym->sym.st_shndx;
+
+ sym->sec = find_section_by_index(elf, shndx);
if (!sym->sec) {
WARN("couldn't find section for symbol %s",
sym->name);
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/3] objtool: optimize insn_hash for split sections
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
2020-04-21 18:07 ` [PATCH 1/3] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
@ 2020-04-21 18:07 ` Sami Tolvanen
2020-04-21 19:47 ` Peter Zijlstra
2020-04-21 18:07 ` [PATCH 3/3] objtool: optimize add_dead_ends " Sami Tolvanen
` (2 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 18:07 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra; +Cc: Kees Cook, linux-kernel, Sami Tolvanen
When running objtool on vmlinux.o compiled with -ffunction-sections,
we end up with a ton of collisions in the insn_hash table as each
function is in its own section. This results in a runtime of minutes
instead of seconds. Use both section index and offset as the key to
avoid this, similarly to rela_hash.
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
tools/objtool/check.c | 5 +++--
tools/objtool/check.h | 5 +++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4b170fd08a28..4770fb07b365 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -34,7 +34,8 @@ struct instruction *find_insn(struct objtool_file *file,
{
struct instruction *insn;
- hash_for_each_possible(file->insn_hash, insn, hash, offset)
+ hash_for_each_possible(file->insn_hash, insn, hash,
+ sec_offset_hash(sec, offset))
if (insn->sec == sec && insn->offset == offset)
return insn;
@@ -273,7 +274,7 @@ static int decode_instructions(struct objtool_file *file)
if (ret)
goto err;
- hash_add(file->insn_hash, &insn->hash, insn->offset);
+ hash_add(file->insn_hash, &insn->hash, insn_hash(insn));
list_add_tail(&insn->list, &file->insn_list);
nr_insns++;
}
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index f0ce8ffe7135..bc78eca7982e 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -56,6 +56,11 @@ struct objtool_file {
int check(const char *objname, bool orc);
+static inline u32 insn_hash(struct instruction *insn)
+{
+ return sec_offset_hash(insn->sec, insn->offset);
+}
+
struct instruction *find_insn(struct objtool_file *file,
struct section *sec, unsigned long offset);
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/3] objtool: optimize add_dead_ends for split sections
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
2020-04-21 18:07 ` [PATCH 1/3] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
2020-04-21 18:07 ` [PATCH 2/3] objtool: optimize insn_hash for split sections Sami Tolvanen
@ 2020-04-21 18:07 ` Sami Tolvanen
2020-04-21 20:13 ` Josh Poimboeuf
2020-04-21 20:14 ` Kees Cook
2020-04-21 20:11 ` [PATCH 0/3] objtool: add support for >64k sections Kees Cook
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
4 siblings, 2 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 18:07 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra; +Cc: Kees Cook, linux-kernel, Sami Tolvanen
When running objtool on vmlinux.o compiled with -ffunction-sections,
.rela.discard.(un)reachable often contains relocations that point to
a different section. Instead of iterating through the list of all
instructions each time, store a pointer to the last instruction of
each section when decoding instructions.
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
tools/objtool/check.c | 43 ++++++++++++++++++++++++++-----------------
tools/objtool/check.h | 4 ++++
tools/objtool/elf.h | 1 +
3 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4770fb07b365..7d4104de0a5e 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -237,6 +237,7 @@ static void clear_insn_state(struct insn_state *state)
static int decode_instructions(struct objtool_file *file)
{
struct section *sec;
+ struct section_info *sec_info = NULL;
struct symbol *func;
unsigned long offset;
struct instruction *insn;
@@ -253,6 +254,8 @@ static int decode_instructions(struct objtool_file *file)
strncmp(sec->name, ".discard.", 9))
sec->text = true;
+ insn = NULL;
+
for (offset = 0; offset < sec->len; offset += insn->len) {
insn = malloc(sizeof(*insn));
if (!insn) {
@@ -279,6 +282,17 @@ static int decode_instructions(struct objtool_file *file)
nr_insns++;
}
+ if (insn) {
+ sec_info = malloc(sizeof(*sec_info));
+ if (!sec_info) {
+ WARN("malloc failed");
+ return -1;
+ }
+
+ sec_info->last_insn = insn;
+ sec->section_info = sec_info;
+ }
+
list_for_each_entry(func, &sec->symbol_list, list) {
if (func->type != STT_FUNC || func->alias != func)
continue;
@@ -312,7 +326,6 @@ static int add_dead_ends(struct objtool_file *file)
struct section *sec;
struct rela *rela;
struct instruction *insn;
- bool found;
/*
* By default, "ud2" is a dead end unless otherwise annotated, because
@@ -338,15 +351,13 @@ static int add_dead_ends(struct objtool_file *file)
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
+ struct section_info *sec_info = (struct section_info *)
+ rela->sym->sec->section_info;
+
+ if (sec_info)
+ insn = sec_info->last_insn;
- if (!found) {
+ if (!insn) {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
@@ -380,15 +391,13 @@ static int add_dead_ends(struct objtool_file *file)
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
+ struct section_info *sec_info = (struct section_info *)
+ rela->sym->sec->section_info;
+
+ if (sec_info)
+ insn = sec_info->last_insn;
- if (!found) {
+ if (!insn) {
WARN("can't find reachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index bc78eca7982e..353677ec85d4 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -47,6 +47,10 @@ struct instruction {
struct orc_entry orc;
};
+struct section_info {
+ struct instruction *last_insn;
+};
+
struct objtool_file {
struct elf *elf;
struct list_head insn_list;
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index ebbb10c61e24..98f2b41d18e4 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -40,6 +40,7 @@ struct section {
int idx;
unsigned int len;
bool changed, text, rodata;
+ void *section_info;
};
struct symbol {
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] objtool: optimize insn_hash for split sections
2020-04-21 18:07 ` [PATCH 2/3] objtool: optimize insn_hash for split sections Sami Tolvanen
@ 2020-04-21 19:47 ` Peter Zijlstra
2020-04-21 20:13 ` Kees Cook
2020-04-21 20:20 ` Sami Tolvanen
0 siblings, 2 replies; 20+ messages in thread
From: Peter Zijlstra @ 2020-04-21 19:47 UTC (permalink / raw)
To: Sami Tolvanen; +Cc: Josh Poimboeuf, Kees Cook, linux-kernel
On Tue, Apr 21, 2020 at 11:07:23AM -0700, Sami Tolvanen wrote:
> When running objtool on vmlinux.o compiled with -ffunction-sections,
> we end up with a ton of collisions in the insn_hash table as each
> function is in its own section. This results in a runtime of minutes
> instead of seconds. Use both section index and offset as the key to
> avoid this, similarly to rela_hash.
>
> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
I already have this queued:
https://lkml.kernel.org/r/20200416115119.227240432@infradead.org
which looks very similar.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/3] objtool: add support for >64k sections
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
` (2 preceding siblings ...)
2020-04-21 18:07 ` [PATCH 3/3] objtool: optimize add_dead_ends " Sami Tolvanen
@ 2020-04-21 20:11 ` Kees Cook
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
4 siblings, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 20:11 UTC (permalink / raw)
To: Sami Tolvanen
Cc: Josh Poimboeuf, Peter Zijlstra, linux-kernel, Kristen Carlson Accardi
On Tue, Apr 21, 2020 at 11:07:21AM -0700, Sami Tolvanen wrote:
> This series fixes objtool for binaries with >64k sections, and
> includes optimizations to reduce the runtime for a binary with
> ~130k sections from >15 minutes to ~4 seconds.
>
> Sami Tolvanen (3):
> objtool: use gelf_getsymshndx to handle >64k sections
> objtool: optimize insn_hash for split sections
> objtool: optimize add_dead_ends for split sections
>
> tools/objtool/check.c | 48 ++++++++++++++++++++++++++-----------------
> tools/objtool/check.h | 9 ++++++++
> tools/objtool/elf.c | 24 +++++++++++++++-------
> tools/objtool/elf.h | 1 +
> 4 files changed, 56 insertions(+), 26 deletions(-)
>
>
> base-commit: ae83d0b416db002fe95601e7f97f64b59514d936
Awesome; thanks for sending these. I suspect they'll help with FGKASLR
as well.
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] objtool: use gelf_getsymshndx to handle >64k sections
2020-04-21 18:07 ` [PATCH 1/3] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
@ 2020-04-21 20:11 ` Kees Cook
0 siblings, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 20:11 UTC (permalink / raw)
To: Sami Tolvanen; +Cc: Josh Poimboeuf, Peter Zijlstra, linux-kernel
On Tue, Apr 21, 2020 at 11:07:22AM -0700, Sami Tolvanen wrote:
> Currently, objtool fails to load the correct section for symbols when
> the index is greater than SHN_LORESERVE. Use gelf_getsymshndx instead
> of gelf_getsym to handle >64k sections.
>
> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> ---
> tools/objtool/elf.c | 24 +++++++++++++++++-------
> 1 file changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
> index 09ddc8f1def3..887445e87380 100644
> --- a/tools/objtool/elf.c
> +++ b/tools/objtool/elf.c
> @@ -327,12 +327,14 @@ static int read_sections(struct elf *elf)
>
> static int read_symbols(struct elf *elf)
> {
> - struct section *symtab, *sec;
> + struct section *symtab, *symtab_shndx, *sec;
> struct symbol *sym, *pfunc;
> struct list_head *entry;
> struct rb_node *pnode;
> int symbols_nr, i;
> char *coldstr;
> + Elf_Data *shndx_data = NULL;
> + Elf32_Word shndx;
>
> symtab = find_section_by_name(elf, ".symtab");
> if (!symtab) {
> @@ -340,6 +342,10 @@ static int read_symbols(struct elf *elf)
> return -1;
> }
>
> + symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
> + if (symtab_shndx)
> + shndx_data = symtab_shndx->data;
> +
> symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
>
> for (i = 0; i < symbols_nr; i++) {
> @@ -353,8 +359,9 @@ static int read_symbols(struct elf *elf)
>
> sym->idx = i;
>
> - if (!gelf_getsym(symtab->data, i, &sym->sym)) {
> - WARN_ELF("gelf_getsym");
> + if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
> + &shndx)) {
> + WARN_ELF("gelf_getsymshndx");
> goto err;
> }
>
> @@ -368,10 +375,13 @@ static int read_symbols(struct elf *elf)
> sym->type = GELF_ST_TYPE(sym->sym.st_info);
> sym->bind = GELF_ST_BIND(sym->sym.st_info);
>
> - if (sym->sym.st_shndx > SHN_UNDEF &&
> - sym->sym.st_shndx < SHN_LORESERVE) {
> - sym->sec = find_section_by_index(elf,
> - sym->sym.st_shndx);
> + if ((sym->sym.st_shndx > SHN_UNDEF &&
> + sym->sym.st_shndx < SHN_LORESERVE) ||
> + (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
> + if (sym->sym.st_shndx != SHN_XINDEX)
> + shndx = sym->sym.st_shndx;
> +
> + sym->sec = find_section_by_index(elf, shndx);
> if (!sym->sec) {
> WARN("couldn't find section for symbol %s",
> sym->name);
> --
> 2.26.1.301.g55bc3eb7cb9-goog
>
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] objtool: optimize add_dead_ends for split sections
2020-04-21 18:07 ` [PATCH 3/3] objtool: optimize add_dead_ends " Sami Tolvanen
@ 2020-04-21 20:13 ` Josh Poimboeuf
2020-04-21 20:17 ` Kees Cook
2020-04-21 22:02 ` Sami Tolvanen
2020-04-21 20:14 ` Kees Cook
1 sibling, 2 replies; 20+ messages in thread
From: Josh Poimboeuf @ 2020-04-21 20:13 UTC (permalink / raw)
To: Sami Tolvanen; +Cc: Peter Zijlstra, Kees Cook, linux-kernel
On Tue, Apr 21, 2020 at 11:07:24AM -0700, Sami Tolvanen wrote:
> @@ -338,15 +351,13 @@ static int add_dead_ends(struct objtool_file *file)
> if (insn)
> insn = list_prev_entry(insn, list);
> else if (rela->addend == rela->sym->sec->len) {
> - found = false;
> - list_for_each_entry_reverse(insn, &file->insn_list, list) {
> - if (insn->sec == rela->sym->sec) {
> - found = true;
> - break;
> - }
> - }
> + struct section_info *sec_info = (struct section_info *)
> + rela->sym->sec->section_info;
> +
> + if (sec_info)
> + insn = sec_info->last_insn;
>
> - if (!found) {
> + if (!insn) {
> WARN("can't find unreachable insn at %s+0x%x",
> rela->sym->sec->name, rela->addend);
> return -1;
Instead of the 'section_info' abstraction I think I'd rather just store
the 'last_insn' pointer directly in the section struct.
Also, the unreachable annotation at the end of a section is really an
edge case. I'm sort of wondering if there's a way to accomplish the
same thing without storing the last_insn.
For example, I wonder if we could use find_insn() for some bytes at the
end of the section. Most of the time I _think_ there will be a two-byte
UD2 instruction there anyway. So maybe we could do something like:
for (offset = rela->sym->sec->len - 1;
offset > rela->sym->sec->len - 10;
offset --) {
insn = find_insn(file, rela->sym->sec, offset);
if (insn)
break;
}
It's kind of ugly, but then we could maybe avoid the need for the
last_insn thing.
BTW, just curious, what's your use case for -ffunction-sections? Is it
for fgkaslr?
--
Josh
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] objtool: optimize insn_hash for split sections
2020-04-21 19:47 ` Peter Zijlstra
@ 2020-04-21 20:13 ` Kees Cook
2020-04-21 20:20 ` Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 20:13 UTC (permalink / raw)
To: Peter Zijlstra; +Cc: Sami Tolvanen, Josh Poimboeuf, linux-kernel
On Tue, Apr 21, 2020 at 09:47:49PM +0200, Peter Zijlstra wrote:
> On Tue, Apr 21, 2020 at 11:07:23AM -0700, Sami Tolvanen wrote:
> > When running objtool on vmlinux.o compiled with -ffunction-sections,
> > we end up with a ton of collisions in the insn_hash table as each
> > function is in its own section. This results in a runtime of minutes
> > instead of seconds. Use both section index and offset as the key to
> > avoid this, similarly to rela_hash.
> >
> > Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
>
> I already have this queued:
>
> https://lkml.kernel.org/r/20200416115119.227240432@infradead.org
>
> which looks very similar.
Ah! Yeah, just no insn-arg helper to do the hash call; cool.
Please consider both:
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] objtool: optimize add_dead_ends for split sections
2020-04-21 18:07 ` [PATCH 3/3] objtool: optimize add_dead_ends " Sami Tolvanen
2020-04-21 20:13 ` Josh Poimboeuf
@ 2020-04-21 20:14 ` Kees Cook
1 sibling, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 20:14 UTC (permalink / raw)
To: Sami Tolvanen; +Cc: Josh Poimboeuf, Peter Zijlstra, linux-kernel
On Tue, Apr 21, 2020 at 11:07:24AM -0700, Sami Tolvanen wrote:
> When running objtool on vmlinux.o compiled with -ffunction-sections,
> .rela.discard.(un)reachable often contains relocations that point to
> a different section. Instead of iterating through the list of all
> instructions each time, store a pointer to the last instruction of
> each section when decoding instructions.
>
> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> ---
> tools/objtool/check.c | 43 ++++++++++++++++++++++++++-----------------
> tools/objtool/check.h | 4 ++++
> tools/objtool/elf.h | 1 +
> 3 files changed, 31 insertions(+), 17 deletions(-)
>
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 4770fb07b365..7d4104de0a5e 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -237,6 +237,7 @@ static void clear_insn_state(struct insn_state *state)
> static int decode_instructions(struct objtool_file *file)
> {
> struct section *sec;
> + struct section_info *sec_info = NULL;
> struct symbol *func;
> unsigned long offset;
> struct instruction *insn;
> @@ -253,6 +254,8 @@ static int decode_instructions(struct objtool_file *file)
> strncmp(sec->name, ".discard.", 9))
> sec->text = true;
>
> + insn = NULL;
> +
> for (offset = 0; offset < sec->len; offset += insn->len) {
> insn = malloc(sizeof(*insn));
> if (!insn) {
> @@ -279,6 +282,17 @@ static int decode_instructions(struct objtool_file *file)
> nr_insns++;
> }
>
> + if (insn) {
> + sec_info = malloc(sizeof(*sec_info));
> + if (!sec_info) {
> + WARN("malloc failed");
> + return -1;
> + }
> +
> + sec_info->last_insn = insn;
> + sec->section_info = sec_info;
> + }
> +
> list_for_each_entry(func, &sec->symbol_list, list) {
> if (func->type != STT_FUNC || func->alias != func)
> continue;
> @@ -312,7 +326,6 @@ static int add_dead_ends(struct objtool_file *file)
> struct section *sec;
> struct rela *rela;
> struct instruction *insn;
> - bool found;
>
> /*
> * By default, "ud2" is a dead end unless otherwise annotated, because
> @@ -338,15 +351,13 @@ static int add_dead_ends(struct objtool_file *file)
> if (insn)
> insn = list_prev_entry(insn, list);
> else if (rela->addend == rela->sym->sec->len) {
> - found = false;
> - list_for_each_entry_reverse(insn, &file->insn_list, list) {
> - if (insn->sec == rela->sym->sec) {
> - found = true;
> - break;
> - }
> - }
> + struct section_info *sec_info = (struct section_info *)
> + rela->sym->sec->section_info;
> +
> + if (sec_info)
> + insn = sec_info->last_insn;
>
> - if (!found) {
> + if (!insn) {
> WARN("can't find unreachable insn at %s+0x%x",
> rela->sym->sec->name, rela->addend);
> return -1;
> @@ -380,15 +391,13 @@ static int add_dead_ends(struct objtool_file *file)
> if (insn)
> insn = list_prev_entry(insn, list);
> else if (rela->addend == rela->sym->sec->len) {
> - found = false;
> - list_for_each_entry_reverse(insn, &file->insn_list, list) {
> - if (insn->sec == rela->sym->sec) {
> - found = true;
> - break;
> - }
> - }
> + struct section_info *sec_info = (struct section_info *)
> + rela->sym->sec->section_info;
> +
> + if (sec_info)
> + insn = sec_info->last_insn;
>
> - if (!found) {
> + if (!insn) {
> WARN("can't find reachable insn at %s+0x%x",
> rela->sym->sec->name, rela->addend);
> return -1;
> diff --git a/tools/objtool/check.h b/tools/objtool/check.h
> index bc78eca7982e..353677ec85d4 100644
> --- a/tools/objtool/check.h
> +++ b/tools/objtool/check.h
> @@ -47,6 +47,10 @@ struct instruction {
> struct orc_entry orc;
> };
>
> +struct section_info {
> + struct instruction *last_insn;
> +};
> +
> struct objtool_file {
> struct elf *elf;
> struct list_head insn_list;
> diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
> index ebbb10c61e24..98f2b41d18e4 100644
> --- a/tools/objtool/elf.h
> +++ b/tools/objtool/elf.h
> @@ -40,6 +40,7 @@ struct section {
> int idx;
> unsigned int len;
> bool changed, text, rodata;
> + void *section_info;
> };
>
> struct symbol {
> --
> 2.26.1.301.g55bc3eb7cb9-goog
>
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] objtool: optimize add_dead_ends for split sections
2020-04-21 20:13 ` Josh Poimboeuf
@ 2020-04-21 20:17 ` Kees Cook
2020-04-21 22:02 ` Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 20:17 UTC (permalink / raw)
To: Josh Poimboeuf; +Cc: Sami Tolvanen, Peter Zijlstra, linux-kernel
On Tue, Apr 21, 2020 at 03:13:05PM -0500, Josh Poimboeuf wrote:
> BTW, just curious, what's your use case for -ffunction-sections? Is it
> for fgkaslr?
Both Sami's LTO+CFI work[1] and Kristen's FGKASLR series use it.
-Kees
[1] https://github.com/samitolvanen/linux/commits/clang-cfi
https://lwn.net/Articles/810077/
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] objtool: optimize insn_hash for split sections
2020-04-21 19:47 ` Peter Zijlstra
2020-04-21 20:13 ` Kees Cook
@ 2020-04-21 20:20 ` Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 20:20 UTC (permalink / raw)
To: Peter Zijlstra; +Cc: Josh Poimboeuf, Kees Cook, linux-kernel
On Tue, Apr 21, 2020 at 09:47:49PM +0200, Peter Zijlstra wrote:
> On Tue, Apr 21, 2020 at 11:07:23AM -0700, Sami Tolvanen wrote:
> > When running objtool on vmlinux.o compiled with -ffunction-sections,
> > we end up with a ton of collisions in the insn_hash table as each
> > function is in its own section. This results in a runtime of minutes
> > instead of seconds. Use both section index and offset as the key to
> > avoid this, similarly to rela_hash.
> >
> > Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
>
> I already have this queued:
>
> https://lkml.kernel.org/r/20200416115119.227240432@infradead.org
>
> which looks very similar.
Great, that works for me. Thanks for the link!
Sami
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] objtool: optimize add_dead_ends for split sections
2020-04-21 20:13 ` Josh Poimboeuf
2020-04-21 20:17 ` Kees Cook
@ 2020-04-21 22:02 ` Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 22:02 UTC (permalink / raw)
To: Josh Poimboeuf; +Cc: Peter Zijlstra, Kees Cook, linux-kernel
On Tue, Apr 21, 2020 at 03:13:05PM -0500, Josh Poimboeuf wrote:
> Also, the unreachable annotation at the end of a section is really an
> edge case. I'm sort of wondering if there's a way to accomplish the
> same thing without storing the last_insn.
>
> For example, I wonder if we could use find_insn() for some bytes at the
> end of the section. Most of the time I _think_ there will be a two-byte
> UD2 instruction there anyway. So maybe we could do something like:
>
> for (offset = rela->sym->sec->len - 1;
> offset > rela->sym->sec->len - 10;
> offset --) {
>
> insn = find_insn(file, rela->sym->sec, offset);
> if (insn)
> break;
> }
>
> It's kind of ugly, but then we could maybe avoid the need for the
> last_insn thing.
Sure, that looks fine. I tested this and it looks like the performance
is roughly the same. I'll send v2 shortly.
Sami
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v2 0/2] objtool: add support for >64k sections
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
` (3 preceding siblings ...)
2020-04-21 20:11 ` [PATCH 0/3] objtool: add support for >64k sections Kees Cook
@ 2020-04-21 22:08 ` Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
` (2 more replies)
4 siblings, 3 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 22:08 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra
Cc: Kees Cook, Kristen Carlson Accardi, linux-kernel, Sami Tolvanen
This series fixes objtool for binaries with >64k sections, and
includes optimizations to reduce the runtime for a binary with
~130k sections from >15 minutes to ~4 seconds.
Changes in v2:
- Dropped the insn_hash optimization as Peter has a nearly
similar change queued already.
- Instead of storing the last instruction for each section,
use find_insn to locate it.
Sami Tolvanen (2):
objtool: use gelf_getsymshndx to handle >64k sections
objtool: optimize add_dead_ends for split sections
tools/objtool/check.c | 36 +++++++++++++++++-------------------
tools/objtool/elf.c | 24 +++++++++++++++++-------
2 files changed, 34 insertions(+), 26 deletions(-)
base-commit: 18bf34080c4c3beb6699181986cc97dd712498fe
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle >64k sections
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
@ 2020-04-21 22:08 ` Sami Tolvanen
2020-05-15 17:22 ` [tip: objtool/core] " tip-bot2 for Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections Sami Tolvanen
2020-04-21 23:52 ` [PATCH v2 0/2] objtool: add support for >64k sections Josh Poimboeuf
2 siblings, 1 reply; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 22:08 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra
Cc: Kees Cook, Kristen Carlson Accardi, linux-kernel, Sami Tolvanen
Currently, objtool fails to load the correct section for symbols when
the index is greater than SHN_LORESERVE. Use gelf_getsymshndx instead
of gelf_getsym to handle >64k sections.
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
---
tools/objtool/elf.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 09ddc8f1def3..887445e87380 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -327,12 +327,14 @@ static int read_sections(struct elf *elf)
static int read_symbols(struct elf *elf)
{
- struct section *symtab, *sec;
+ struct section *symtab, *symtab_shndx, *sec;
struct symbol *sym, *pfunc;
struct list_head *entry;
struct rb_node *pnode;
int symbols_nr, i;
char *coldstr;
+ Elf_Data *shndx_data = NULL;
+ Elf32_Word shndx;
symtab = find_section_by_name(elf, ".symtab");
if (!symtab) {
@@ -340,6 +342,10 @@ static int read_symbols(struct elf *elf)
return -1;
}
+ symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+ if (symtab_shndx)
+ shndx_data = symtab_shndx->data;
+
symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
for (i = 0; i < symbols_nr; i++) {
@@ -353,8 +359,9 @@ static int read_symbols(struct elf *elf)
sym->idx = i;
- if (!gelf_getsym(symtab->data, i, &sym->sym)) {
- WARN_ELF("gelf_getsym");
+ if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
+ &shndx)) {
+ WARN_ELF("gelf_getsymshndx");
goto err;
}
@@ -368,10 +375,13 @@ static int read_symbols(struct elf *elf)
sym->type = GELF_ST_TYPE(sym->sym.st_info);
sym->bind = GELF_ST_BIND(sym->sym.st_info);
- if (sym->sym.st_shndx > SHN_UNDEF &&
- sym->sym.st_shndx < SHN_LORESERVE) {
- sym->sec = find_section_by_index(elf,
- sym->sym.st_shndx);
+ if ((sym->sym.st_shndx > SHN_UNDEF &&
+ sym->sym.st_shndx < SHN_LORESERVE) ||
+ (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
+ if (sym->sym.st_shndx != SHN_XINDEX)
+ shndx = sym->sym.st_shndx;
+
+ sym->sec = find_section_by_index(elf, shndx);
if (!sym->sec) {
WARN("couldn't find section for symbol %s",
sym->name);
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
@ 2020-04-21 22:08 ` Sami Tolvanen
2020-04-21 23:43 ` Kees Cook
2020-05-15 17:22 ` [tip: objtool/core] " tip-bot2 for Sami Tolvanen
2020-04-21 23:52 ` [PATCH v2 0/2] objtool: add support for >64k sections Josh Poimboeuf
2 siblings, 2 replies; 20+ messages in thread
From: Sami Tolvanen @ 2020-04-21 22:08 UTC (permalink / raw)
To: Josh Poimboeuf, Peter Zijlstra
Cc: Kees Cook, Kristen Carlson Accardi, linux-kernel, Sami Tolvanen
Instead of iterating through all instructions to find the last
instruction each time .rela.discard.(un)reachable points beyond the
section, use find_insn to locate the last instruction by looking at
the last bytes of the section instead.
Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
---
tools/objtool/check.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4b170fd08a28..4f1d405420a4 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -303,6 +303,19 @@ static int decode_instructions(struct objtool_file *file)
return ret;
}
+static struct instruction *find_last_insn(struct objtool_file *file,
+ struct section *sec)
+{
+ struct instruction *insn = NULL;
+ unsigned int offset;
+ unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
+
+ for (offset = sec->len - 1; offset >= end && !insn; offset--)
+ insn = find_insn(file, sec, offset);
+
+ return insn;
+}
+
/*
* Mark "ud2" instructions and manually annotated dead ends.
*/
@@ -311,7 +324,6 @@ static int add_dead_ends(struct objtool_file *file)
struct section *sec;
struct rela *rela;
struct instruction *insn;
- bool found;
/*
* By default, "ud2" is a dead end unless otherwise annotated, because
@@ -337,15 +349,8 @@ static int add_dead_ends(struct objtool_file *file)
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
-
- if (!found) {
+ insn = find_last_insn(file, rela->sym->sec);
+ if (!insn) {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
@@ -379,15 +384,8 @@ static int add_dead_ends(struct objtool_file *file)
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
-
- if (!found) {
+ insn = find_last_insn(file, rela->sym->sec);
+ if (!insn) {
WARN("can't find reachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
--
2.26.1.301.g55bc3eb7cb9-goog
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections
2020-04-21 22:08 ` [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections Sami Tolvanen
@ 2020-04-21 23:43 ` Kees Cook
2020-05-15 17:22 ` [tip: objtool/core] " tip-bot2 for Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: Kees Cook @ 2020-04-21 23:43 UTC (permalink / raw)
To: Sami Tolvanen
Cc: Josh Poimboeuf, Peter Zijlstra, Kristen Carlson Accardi, linux-kernel
On Tue, Apr 21, 2020 at 03:08:43PM -0700, Sami Tolvanen wrote:
> Instead of iterating through all instructions to find the last
> instruction each time .rela.discard.(un)reachable points beyond the
> section, use find_insn to locate the last instruction by looking at
> the last bytes of the section instead.
>
> Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
-Kees
> ---
> tools/objtool/check.c | 36 +++++++++++++++++-------------------
> 1 file changed, 17 insertions(+), 19 deletions(-)
>
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 4b170fd08a28..4f1d405420a4 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -303,6 +303,19 @@ static int decode_instructions(struct objtool_file *file)
> return ret;
> }
>
> +static struct instruction *find_last_insn(struct objtool_file *file,
> + struct section *sec)
> +{
> + struct instruction *insn = NULL;
> + unsigned int offset;
> + unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
> +
> + for (offset = sec->len - 1; offset >= end && !insn; offset--)
> + insn = find_insn(file, sec, offset);
> +
> + return insn;
> +}
> +
> /*
> * Mark "ud2" instructions and manually annotated dead ends.
> */
> @@ -311,7 +324,6 @@ static int add_dead_ends(struct objtool_file *file)
> struct section *sec;
> struct rela *rela;
> struct instruction *insn;
> - bool found;
>
> /*
> * By default, "ud2" is a dead end unless otherwise annotated, because
> @@ -337,15 +349,8 @@ static int add_dead_ends(struct objtool_file *file)
> if (insn)
> insn = list_prev_entry(insn, list);
> else if (rela->addend == rela->sym->sec->len) {
> - found = false;
> - list_for_each_entry_reverse(insn, &file->insn_list, list) {
> - if (insn->sec == rela->sym->sec) {
> - found = true;
> - break;
> - }
> - }
> -
> - if (!found) {
> + insn = find_last_insn(file, rela->sym->sec);
> + if (!insn) {
> WARN("can't find unreachable insn at %s+0x%x",
> rela->sym->sec->name, rela->addend);
> return -1;
> @@ -379,15 +384,8 @@ static int add_dead_ends(struct objtool_file *file)
> if (insn)
> insn = list_prev_entry(insn, list);
> else if (rela->addend == rela->sym->sec->len) {
> - found = false;
> - list_for_each_entry_reverse(insn, &file->insn_list, list) {
> - if (insn->sec == rela->sym->sec) {
> - found = true;
> - break;
> - }
> - }
> -
> - if (!found) {
> + insn = find_last_insn(file, rela->sym->sec);
> + if (!insn) {
> WARN("can't find reachable insn at %s+0x%x",
> rela->sym->sec->name, rela->addend);
> return -1;
> --
> 2.26.1.301.g55bc3eb7cb9-goog
>
--
Kees Cook
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 0/2] objtool: add support for >64k sections
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections Sami Tolvanen
@ 2020-04-21 23:52 ` Josh Poimboeuf
2 siblings, 0 replies; 20+ messages in thread
From: Josh Poimboeuf @ 2020-04-21 23:52 UTC (permalink / raw)
To: Sami Tolvanen
Cc: Peter Zijlstra, Kees Cook, Kristen Carlson Accardi, linux-kernel
On Tue, Apr 21, 2020 at 03:08:41PM -0700, Sami Tolvanen wrote:
> This series fixes objtool for binaries with >64k sections, and
> includes optimizations to reduce the runtime for a binary with
> ~130k sections from >15 minutes to ~4 seconds.
>
> Changes in v2:
> - Dropped the insn_hash optimization as Peter has a nearly
> similar change queued already.
> - Instead of storing the last instruction for each section,
> use find_insn to locate it.
>
>
> Sami Tolvanen (2):
> objtool: use gelf_getsymshndx to handle >64k sections
> objtool: optimize add_dead_ends for split sections
>
> tools/objtool/check.c | 36 +++++++++++++++++-------------------
> tools/objtool/elf.c | 24 +++++++++++++++++-------
> 2 files changed, 34 insertions(+), 26 deletions(-)
>
>
> base-commit: 18bf34080c4c3beb6699181986cc97dd712498fe
Looks good to me, thanks. I'll add them to the queue for testing, along
with that other patch.
--
Josh
^ permalink raw reply [flat|nested] 20+ messages in thread
* [tip: objtool/core] objtool: optimize add_dead_ends for split sections
2020-04-21 22:08 ` [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections Sami Tolvanen
2020-04-21 23:43 ` Kees Cook
@ 2020-05-15 17:22 ` tip-bot2 for Sami Tolvanen
1 sibling, 0 replies; 20+ messages in thread
From: tip-bot2 for Sami Tolvanen @ 2020-05-15 17:22 UTC (permalink / raw)
To: linux-tip-commits
Cc: Josh Poimboeuf, Sami Tolvanen, Peter Zijlstra (Intel), x86, LKML
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 6b5dd716da8fc3aba65e6b7d992dea0cee2f9528
Gitweb: https://git.kernel.org/tip/6b5dd716da8fc3aba65e6b7d992dea0cee2f9528
Author: Sami Tolvanen <samitolvanen@google.com>
AuthorDate: Tue, 21 Apr 2020 15:08:43 -07:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 15 May 2020 10:35:13 +02:00
objtool: optimize add_dead_ends for split sections
Instead of iterating through all instructions to find the last
instruction each time .rela.discard.(un)reachable points beyond the
section, use find_insn to locate the last instruction by looking at
the last bytes of the section instead.
Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20200421220843.188260-3-samitolvanen@google.com
---
tools/objtool/check.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 196a551..6b2b458 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -322,6 +322,19 @@ err:
return ret;
}
+static struct instruction *find_last_insn(struct objtool_file *file,
+ struct section *sec)
+{
+ struct instruction *insn = NULL;
+ unsigned int offset;
+ unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
+
+ for (offset = sec->len - 1; offset >= end && !insn; offset--)
+ insn = find_insn(file, sec, offset);
+
+ return insn;
+}
+
/*
* Mark "ud2" instructions and manually annotated dead ends.
*/
@@ -330,7 +343,6 @@ static int add_dead_ends(struct objtool_file *file)
struct section *sec;
struct rela *rela;
struct instruction *insn;
- bool found;
/*
* By default, "ud2" is a dead end unless otherwise annotated, because
@@ -356,15 +368,8 @@ static int add_dead_ends(struct objtool_file *file)
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
-
- if (!found) {
+ insn = find_last_insn(file, rela->sym->sec);
+ if (!insn) {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
@@ -398,15 +403,8 @@ reachable:
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
- found = false;
- list_for_each_entry_reverse(insn, &file->insn_list, list) {
- if (insn->sec == rela->sym->sec) {
- found = true;
- break;
- }
- }
-
- if (!found) {
+ insn = find_last_insn(file, rela->sym->sec);
+ if (!insn) {
WARN("can't find reachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [tip: objtool/core] objtool: use gelf_getsymshndx to handle >64k sections
2020-04-21 22:08 ` [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
@ 2020-05-15 17:22 ` tip-bot2 for Sami Tolvanen
0 siblings, 0 replies; 20+ messages in thread
From: tip-bot2 for Sami Tolvanen @ 2020-05-15 17:22 UTC (permalink / raw)
To: linux-tip-commits
Cc: Sami Tolvanen, Peter Zijlstra (Intel), Kees Cook, x86, LKML
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: 28fe1d7bf89f8ed5be70b98a33932dbaf99345dd
Gitweb: https://git.kernel.org/tip/28fe1d7bf89f8ed5be70b98a33932dbaf99345dd
Author: Sami Tolvanen <samitolvanen@google.com>
AuthorDate: Tue, 21 Apr 2020 15:08:42 -07:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 15 May 2020 10:35:13 +02:00
objtool: use gelf_getsymshndx to handle >64k sections
Currently, objtool fails to load the correct section for symbols when
the index is greater than SHN_LORESERVE. Use gelf_getsymshndx instead
of gelf_getsym to handle >64k sections.
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lkml.kernel.org/r/20200421220843.188260-2-samitolvanen@google.com
---
tools/objtool/elf.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index b6349ca..8422567 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -343,12 +343,14 @@ static int read_sections(struct elf *elf)
static int read_symbols(struct elf *elf)
{
- struct section *symtab, *sec;
+ struct section *symtab, *symtab_shndx, *sec;
struct symbol *sym, *pfunc;
struct list_head *entry;
struct rb_node *pnode;
int symbols_nr, i;
char *coldstr;
+ Elf_Data *shndx_data = NULL;
+ Elf32_Word shndx;
symtab = find_section_by_name(elf, ".symtab");
if (!symtab) {
@@ -356,6 +358,10 @@ static int read_symbols(struct elf *elf)
return -1;
}
+ symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+ if (symtab_shndx)
+ shndx_data = symtab_shndx->data;
+
symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
for (i = 0; i < symbols_nr; i++) {
@@ -369,8 +375,9 @@ static int read_symbols(struct elf *elf)
sym->idx = i;
- if (!gelf_getsym(symtab->data, i, &sym->sym)) {
- WARN_ELF("gelf_getsym");
+ if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
+ &shndx)) {
+ WARN_ELF("gelf_getsymshndx");
goto err;
}
@@ -384,10 +391,13 @@ static int read_symbols(struct elf *elf)
sym->type = GELF_ST_TYPE(sym->sym.st_info);
sym->bind = GELF_ST_BIND(sym->sym.st_info);
- if (sym->sym.st_shndx > SHN_UNDEF &&
- sym->sym.st_shndx < SHN_LORESERVE) {
- sym->sec = find_section_by_index(elf,
- sym->sym.st_shndx);
+ if ((sym->sym.st_shndx > SHN_UNDEF &&
+ sym->sym.st_shndx < SHN_LORESERVE) ||
+ (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
+ if (sym->sym.st_shndx != SHN_XINDEX)
+ shndx = sym->sym.st_shndx;
+
+ sym->sec = find_section_by_index(elf, shndx);
if (!sym->sec) {
WARN("couldn't find section for symbol %s",
sym->name);
^ permalink raw reply related [flat|nested] 20+ messages in thread
end of thread, other threads:[~2020-05-15 17:23 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-21 18:07 [PATCH 0/3] objtool: add support for >64k sections Sami Tolvanen
2020-04-21 18:07 ` [PATCH 1/3] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
2020-04-21 20:11 ` Kees Cook
2020-04-21 18:07 ` [PATCH 2/3] objtool: optimize insn_hash for split sections Sami Tolvanen
2020-04-21 19:47 ` Peter Zijlstra
2020-04-21 20:13 ` Kees Cook
2020-04-21 20:20 ` Sami Tolvanen
2020-04-21 18:07 ` [PATCH 3/3] objtool: optimize add_dead_ends " Sami Tolvanen
2020-04-21 20:13 ` Josh Poimboeuf
2020-04-21 20:17 ` Kees Cook
2020-04-21 22:02 ` Sami Tolvanen
2020-04-21 20:14 ` Kees Cook
2020-04-21 20:11 ` [PATCH 0/3] objtool: add support for >64k sections Kees Cook
2020-04-21 22:08 ` [PATCH v2 0/2] " Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 1/2] objtool: use gelf_getsymshndx to handle " Sami Tolvanen
2020-05-15 17:22 ` [tip: objtool/core] " tip-bot2 for Sami Tolvanen
2020-04-21 22:08 ` [PATCH v2 2/2] objtool: optimize add_dead_ends for split sections Sami Tolvanen
2020-04-21 23:43 ` Kees Cook
2020-05-15 17:22 ` [tip: objtool/core] " tip-bot2 for Sami Tolvanen
2020-04-21 23:52 ` [PATCH v2 0/2] objtool: add support for >64k sections Josh Poimboeuf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).