xref: /linux/tools/objtool/tests/generic/test-local-to-global-flip.sh (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1*2bbf68f4SSong Liu#!/bin/bash
2*2bbf68f4SSong Liu# SPDX-License-Identifier: GPL-2.0
3*2bbf68f4SSong Liu#
4*2bbf68f4SSong Liu# A patch can change a symbol's linkage without renaming it: dropping "static"
5*2bbf68f4SSong Liu# from a helper so something else can call it, or adding it to one that is no
6*2bbf68f4SSong Liu# longer shared.  Correlation keys off more than the name, so a symbol whose
7*2bbf68f4SSong Liu# binding moved can fail to pair with itself.
8*2bbf68f4SSong Liu#
9*2bbf68f4SSong Liu# Failing to correlate is not a build failure.  The symbol looks new, and a
10*2bbf68f4SSong Liu# "new" data symbol is either rejected or cloned as a second copy -- at which
11*2bbf68f4SSong Liu# point the patched code updates its own private variable and the rest of the
12*2bbf68f4SSong Liu# kernel keeps reading the original.
13*2bbf68f4SSong Liu
14*2bbf68f4SSong Liu. "$(dirname "$0")/../lib.sh"
15*2bbf68f4SSong Liu
16*2bbf68f4SSong Liusetup
17*2bbf68f4SSong Liubuild_pair local_to_global.c
18*2bbf68f4SSong Liu
19*2bbf68f4SSong Liu# Confirm the fixture really moved the bindings, in both directions.
20*2bbf68f4SSong Liu#
21*2bbf68f4SSong Liu# Match the binding and the name as fields, not as substrings of the line.
22*2bbf68f4SSong Liu# -ffunction-sections and -fdata-sections give these symbols sections of their
23*2bbf68f4SSong Liu# own, and the section symbols -- .text.flipped_up, .data.flipped_down -- are
24*2bbf68f4SSong Liu# always LOCAL, so "does a LOCAL line mention flipped_up" is answered by the
25*2bbf68f4SSong Liu# wrong symbol.  GNU readelf 2.35 happens to leave section symbol names blank,
26*2bbf68f4SSong Liu# but llvm-readelf prints them, and a premise that holds on one readelf and
27*2bbf68f4SSong Liu# not the other is no premise at all.
28*2bbf68f4SSong Liuhas_binding()   # $1 object, $2 binding, $3 symbol
29*2bbf68f4SSong Liu{
30*2bbf68f4SSong Liu	in_symbols "$1" | awk -v b="$2" -v n="$3" '$5 == b && $NF == n' | grep -q .
31*2bbf68f4SSong Liu}
32*2bbf68f4SSong Liu
33*2bbf68f4SSong Liuhas_binding orig.o    LOCAL  flipped_up ||
34*2bbf68f4SSong Liu	fail "flipped_up is not local in the original"
35*2bbf68f4SSong Liuhas_binding patched.o GLOBAL flipped_up ||
36*2bbf68f4SSong Liu	fail "flipped_up is not global in the patched object"
37*2bbf68f4SSong Liuhas_binding orig.o    GLOBAL flipped_down ||
38*2bbf68f4SSong Liu	fail "flipped_down is not global in the original"
39*2bbf68f4SSong Liuhas_binding patched.o LOCAL  flipped_down ||
40*2bbf68f4SSong Liu	fail "flipped_down is not local in the patched object"
41*2bbf68f4SSong Liu
42*2bbf68f4SSong Liurun_diff
43*2bbf68f4SSong Liu
44*2bbf68f4SSong Liuassert_diff_log 'changed function: caller'
45*2bbf68f4SSong Liu
46*2bbf68f4SSong Liu# Correlated means each pairs with its own counterpart in the original, so the
47*2bbf68f4SSong Liu# patch refers back to the kernel's copy ...
48*2bbf68f4SSong Liuassert_klp_sym flipped_up vmlinux
49*2bbf68f4SSong Liuassert_klp_sym flipped_down vmlinux
50*2bbf68f4SSong Liu
51*2bbf68f4SSong Liu# ... rather than carrying its own.  A second copy of flipped_down is the bad
52*2bbf68f4SSong Liu# outcome: patched code would update its private one while the rest of the
53*2bbf68f4SSong Liu# kernel keeps reading the original.
54*2bbf68f4SSong Liuassert_not_patched flipped_up
55*2bbf68f4SSong Liuassert_no_section .data.flipped_down
56*2bbf68f4SSong Liuassert_no_section .bss.flipped_down
57*2bbf68f4SSong Liu
58*2bbf68f4SSong Liudiff_log | grep -q 'no correlation' &&
59*2bbf68f4SSong Liu	fail "linkage change reported as an uncorrelated symbol"
60*2bbf68f4SSong Liudiff_log | grep -q 'changed data' &&
61*2bbf68f4SSong Liu	fail "linkage change reported as changed data"
62*2bbf68f4SSong Liu
63*2bbf68f4SSong Liupass "symbols correlated across a change of linkage"
64