xref: /linux/tools/objtool/tests/generic/test-checksum-position.sh (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
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