Arnd Bergmann reported the following warning with GCC 7.1.1: fs/fs_pin.o: warning: objtool: pin_kill()+0x139: stack state mismatch: cfa1=7+88 cfa2=7+96 And the kbuild robot reported the following warnings with GCC 5.4.1: fs/fs_pin.o: warning: objtool: pin_kill()+0x182: return with modified stack frame fs/quota/dquot.o: warning: objtool: dquot_alloc_inode()+0x140: stack state mismatch: cfa1=7+120 cfa2=7+128 fs/quota/dquot.o: warning: objtool: dquot_free_inode()+0x11a: stack state mismatch: cfa1=7+112 cfa2=7+120 Those warnings are caused by an unusual GCC non-optimization where it uses an intermediate register to adjust the stack pointer. It does: lea 0x8(%rsp), %rcx ... mov %rcx, %rsp Instead of the obvious: add $0x8, %rsp It makes no sense to use an intermediate register, so I opened a GCC bug to track it: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81813 But it's not exactly a high-priority bug and it looks like we'll be stuck with this issue for a while. So for now we have to track register values when they're loaded with stack pointer offsets. This is kind of a big workaround for a tiny problem, but c'est la vie. I hope to eventually create a GCC plugin to implement a big chunk of objtool's functionality. Hopefully at that point we'll be able to remove of a lot of these GCC-isms from the objtool code. Reported-by: Arnd Bergmann <arnd@arndb.de> Reported-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/6a41a96884c725e7f05413bb7df40cfe824b2444.1504028945.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
		
			
				
	
	
		
			81 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #ifndef _CHECK_H
 | |
| #define _CHECK_H
 | |
| 
 | |
| #include <stdbool.h>
 | |
| #include "elf.h"
 | |
| #include "cfi.h"
 | |
| #include "arch.h"
 | |
| #include "orc.h"
 | |
| #include <linux/hashtable.h>
 | |
| 
 | |
| struct insn_state {
 | |
| 	struct cfi_reg cfa;
 | |
| 	struct cfi_reg regs[CFI_NUM_REGS];
 | |
| 	int stack_size;
 | |
| 	unsigned char type;
 | |
| 	bool bp_scratch;
 | |
| 	bool drap;
 | |
| 	int drap_reg, drap_offset;
 | |
| 	struct cfi_reg vals[CFI_NUM_REGS];
 | |
| };
 | |
| 
 | |
| struct instruction {
 | |
| 	struct list_head list;
 | |
| 	struct hlist_node hash;
 | |
| 	struct section *sec;
 | |
| 	unsigned long offset;
 | |
| 	unsigned int len;
 | |
| 	unsigned char type;
 | |
| 	unsigned long immediate;
 | |
| 	bool alt_group, visited, dead_end, ignore, hint, save, restore;
 | |
| 	struct symbol *call_dest;
 | |
| 	struct instruction *jump_dest;
 | |
| 	struct list_head alts;
 | |
| 	struct symbol *func;
 | |
| 	struct stack_op stack_op;
 | |
| 	struct insn_state state;
 | |
| 	struct orc_entry orc;
 | |
| };
 | |
| 
 | |
| struct objtool_file {
 | |
| 	struct elf *elf;
 | |
| 	struct list_head insn_list;
 | |
| 	DECLARE_HASHTABLE(insn_hash, 16);
 | |
| 	struct section *rodata, *whitelist;
 | |
| 	bool ignore_unreachables, c_file, hints;
 | |
| };
 | |
| 
 | |
| int check(const char *objname, bool no_fp, bool no_unreachable, bool orc);
 | |
| 
 | |
| struct instruction *find_insn(struct objtool_file *file,
 | |
| 			      struct section *sec, unsigned long offset);
 | |
| 
 | |
| #define for_each_insn(file, insn)					\
 | |
| 	list_for_each_entry(insn, &file->insn_list, list)
 | |
| 
 | |
| #define sec_for_each_insn(file, sec, insn)				\
 | |
| 	for (insn = find_insn(file, sec, 0);				\
 | |
| 	     insn && &insn->list != &file->insn_list &&			\
 | |
| 			insn->sec == sec;				\
 | |
| 	     insn = list_next_entry(insn, list))
 | |
| 
 | |
| 
 | |
| #endif /* _CHECK_H */
 |