mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	objtool: Support stack-swizzle
Natively support the stack swizzle pattern: mov %rsp, (%[tos]) mov %[tos], %rsp ... pop %rsp It uses the vals[] array to link the first two stack-ops, and detect the SP to SP_INDIRECT swizzle. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
This commit is contained in:
		
							parent
							
								
									2a51282984
								
							
						
					
					
						commit
						aafeb14e9d
					
				
					 1 changed files with 45 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -1945,6 +1945,38 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 | 
			
		|||
					cfa->offset = -cfi->vals[op->src.reg].offset;
 | 
			
		||||
					cfi->stack_size = cfa->offset;
 | 
			
		||||
 | 
			
		||||
				} else if (cfa->base == CFI_SP &&
 | 
			
		||||
					   cfi->vals[op->src.reg].base == CFI_SP_INDIRECT &&
 | 
			
		||||
					   cfi->vals[op->src.reg].offset == cfa->offset) {
 | 
			
		||||
 | 
			
		||||
					/*
 | 
			
		||||
					 * Stack swizzle:
 | 
			
		||||
					 *
 | 
			
		||||
					 * 1: mov %rsp, (%[tos])
 | 
			
		||||
					 * 2: mov %[tos], %rsp
 | 
			
		||||
					 *    ...
 | 
			
		||||
					 * 3: pop %rsp
 | 
			
		||||
					 *
 | 
			
		||||
					 * Where:
 | 
			
		||||
					 *
 | 
			
		||||
					 * 1 - places a pointer to the previous
 | 
			
		||||
					 *     stack at the Top-of-Stack of the
 | 
			
		||||
					 *     new stack.
 | 
			
		||||
					 *
 | 
			
		||||
					 * 2 - switches to the new stack.
 | 
			
		||||
					 *
 | 
			
		||||
					 * 3 - pops the Top-of-Stack to restore
 | 
			
		||||
					 *     the original stack.
 | 
			
		||||
					 *
 | 
			
		||||
					 * Note: we set base to SP_INDIRECT
 | 
			
		||||
					 * here and preserve offset. Therefore
 | 
			
		||||
					 * when the unwinder reaches ToS it
 | 
			
		||||
					 * will dereference SP and then add the
 | 
			
		||||
					 * offset to find the next frame, IOW:
 | 
			
		||||
					 * (%rsp) + offset.
 | 
			
		||||
					 */
 | 
			
		||||
					cfa->base = CFI_SP_INDIRECT;
 | 
			
		||||
 | 
			
		||||
				} else {
 | 
			
		||||
					cfa->base = CFI_UNDEFINED;
 | 
			
		||||
					cfa->offset = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2047,6 +2079,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 | 
			
		|||
 | 
			
		||||
		case OP_SRC_POP:
 | 
			
		||||
		case OP_SRC_POPF:
 | 
			
		||||
			if (op->dest.reg == CFI_SP && cfa->base == CFI_SP_INDIRECT) {
 | 
			
		||||
 | 
			
		||||
				/* pop %rsp; # restore from a stack swizzle */
 | 
			
		||||
				cfa->base = CFI_SP;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!cfi->drap && op->dest.reg == cfa->base) {
 | 
			
		||||
 | 
			
		||||
				/* pop %rbp */
 | 
			
		||||
| 
						 | 
				
			
			@ -2193,6 +2232,12 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 | 
			
		|||
			/* mov reg, disp(%rsp) */
 | 
			
		||||
			save_reg(cfi, op->src.reg, CFI_CFA,
 | 
			
		||||
				 op->dest.offset - cfi->stack_size);
 | 
			
		||||
 | 
			
		||||
		} else if (op->src.reg == CFI_SP && op->dest.offset == 0) {
 | 
			
		||||
 | 
			
		||||
			/* mov %rsp, (%reg); # setup a stack swizzle. */
 | 
			
		||||
			cfi->vals[op->dest.reg].base = CFI_SP_INDIRECT;
 | 
			
		||||
			cfi->vals[op->dest.reg].offset = cfa->offset;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue