1*f55eae8fSSong Liu#!/bin/bash 2*f55eae8fSSong Liu# SPDX-License-Identifier: GPL-2.0 3*f55eae8fSSong Liu# 4*f55eae8fSSong Liu# A function's checksum must not depend on where the function sits. 5*f55eae8fSSong Liu# 6*f55eae8fSSong Liu# A jump or call without a relocation encodes its target as an offset from the 7*f55eae8fSSong Liu# instruction. Hashing those bytes makes the checksum change whenever anything 8*f55eae8fSSong Liu# ahead of the function changes size -- so an unrelated edit elsewhere in the 9*f55eae8fSSong Liu# file reports this function as changed too, and the patch grows to include it 10*f55eae8fSSong Liu# and everything it references. Nothing fails; the livepatch is just larger and 11*f55eae8fSSong Liu# riskier than the patch it came from. 12*f55eae8fSSong Liu# 13*f55eae8fSSong Liu# Here the "patch" moves target() away from callee() and changes nothing else: 14*f55eae8fSSong Liu# both are aligned to 64 in the patched build, which shifts them apart without 15*f55eae8fSSong Liu# touching a byte of either. See the fixture for why it is done that way. 16*f55eae8fSSong Liu 17*f55eae8fSSong Liu. "$(dirname "$0")/../lib.sh" 18*f55eae8fSSong Liu 19*f55eae8fSSong Liusetup 20*f55eae8fSSong Liu 21*f55eae8fSSong Liu# -fno-function-sections, or each function is at offset 0 of its own section 22*f55eae8fSSong Liu# and target() never moves. 23*f55eae8fSSong Liubuild_pair checksum_position.c -fno-function-sections 24*f55eae8fSSong Liu 25*f55eae8fSSong Liuassert_input_symbol target 26*f55eae8fSSong Liu 27*f55eae8fSSong Liu# The fixture is only meaningful if the displacement target's calls encode 28*f55eae8fSSong Liu# actually changed, and that is the distance to callee() -- not target's own 29*f55eae8fSSong Liu# offset. A compiler which shifted the two by the same amount would move 30*f55eae8fSSong Liu# target and leave the distance alone, and then the bytes are identical and 31*f55eae8fSSong Liu# the checksum matches for the uninteresting reason. Ask about the distance. 32*f55eae8fSSong Liusym_off() # $1 object, $2 symbol 33*f55eae8fSSong Liu{ 34*f55eae8fSSong Liu in_symbols "$1" | awk -v n="$2" '$NF == n { print $2; exit }' 35*f55eae8fSSong Liu} 36*f55eae8fSSong Liu 37*f55eae8fSSong Liuorig_t="$(sym_off orig.o target)"; orig_c="$(sym_off orig.o callee)" 38*f55eae8fSSong Liunew_t="$(sym_off patched.o target)"; new_c="$(sym_off patched.o callee)" 39*f55eae8fSSong Liu 40*f55eae8fSSong Liu[ -n "$orig_t" ] && [ -n "$orig_c" ] && [ -n "$new_t" ] && [ -n "$new_c" ] || 41*f55eae8fSSong Liu fail "target or callee missing from one of the objects" 42*f55eae8fSSong Liu 43*f55eae8fSSong Liuorig_gap=$(( 16#$orig_t - 16#$orig_c )) 44*f55eae8fSSong Liunew_gap=$(( 16#$new_t - 16#$new_c )) 45*f55eae8fSSong Liu[ "$orig_gap" != "$new_gap" ] || 46*f55eae8fSSong Liu probe_skip "this compiler kept target() and callee() the same distance" \ 47*f55eae8fSSong Liu "apart; the call displacement did not change" 48*f55eae8fSSong Liu 49*f55eae8fSSong Liuassert_checksum_matches target 50*f55eae8fSSong Liu 51*f55eae8fSSong Liupass "checksum unchanged when the function only moves" 52