All of lore.kernel.org
 help / color / mirror / Atom feed
* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.