summaryrefslogtreecommitdiff
path: root/tests/tst-link-needed-runner.sh
blob: 8f339866943328e92f0a9bc9250390d4320a3b2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/bin/sh
set -eu

: "${CPU_AS:?}" "${CPU_LD:?}" "${CPU_RUN:?}" "${CPU_READELF:?}"

TMP=${TMPDIR:-/tmp}/libmcpu-link-needed-$$
HOME="$TMP/home"
export HOME
mkdir -p "$HOME/.mcpu/etc" "$TMP/root/lib" "$TMP/first"
trap 'rm -rf "$TMP"' EXIT HUP INT TERM

cat > "$TMP/main.s" <<'EOS'
.global _life
.extern foo
.text
_start_life:
        LDI     r64@0x00000, 40
        CALL    foo
        MOV     r64@0x00018, r64@0x00000
        LDI     r32@0x00030, 0
        EXIT    r32@0x00030
EOS

cat > "$TMP/good.s" <<'EOS'
.global foo
.text
foo:
        LDI     r64@0x00008, 2
        IADD    r64@0x00000, r64@0x00000, r64@0x00008
        RET
EOS

cat > "$TMP/alt.s" <<'EOS'
.global foo
.text
foo:
        LDI     r64@0x00008, 3
        IADD    r64@0x00000, r64@0x00000, r64@0x00008
        RET
EOS

cat > "$TMP/bad.s" <<'EOS'
.global other
.text
other:
        RET
EOS

"$CPU_AS" -o "$TMP/main.o" "$TMP/main.s"
"$CPU_AS" -o "$TMP/good.o" "$TMP/good.s"
"$CPU_AS" -o "$TMP/alt.o" "$TMP/alt.s"
"$CPU_AS" -o "$TMP/bad.o" "$TMP/bad.s"

# The development link name is libfoo.so, but the ABI identity recorded in
# DT_NEEDED comes from the validated library SONAME.
"$CPU_LD" --shared --soname=libfoo.so.1 \
  -o "$TMP/root/lib/libfoo.so.1.2.3" "$TMP/good.o"
ln -s libfoo.so.1.2.3 "$TMP/root/lib/libfoo.so.1"
ln -s libfoo.so.1 "$TMP/root/lib/libfoo.so"

"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
  -L"$TMP/root/lib" -lfoo -o "$TMP/main" "$TMP/main.o"
"$CPU_READELF" -d "$TMP/main" > "$TMP/main.dynamic"
grep -q 'NEEDED.*\[libfoo.so.1\]' "$TMP/main.dynamic"
[ "`grep -c 'NEEDED' "$TMP/main.dynamic"`" -eq 1 ]
if grep -q 'libfoo.so.1.2.3' "$TMP/main.dynamic"; then
  echo "DT_NEEDED unexpectedly contains physical library filename" >&2
  exit 1
fi

# The separated -l NAME spelling is equivalent.
"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
  -L "$TMP/root/lib" -l foo -o "$TMP/main-separated" "$TMP/main.o"
"$CPU_READELF" -d "$TMP/main-separated" | grep -q 'NEEDED.*\[libfoo.so.1\]'

# Repeated requests resolving to the same SONAME produce one dependency.
"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
  -L"$TMP/root/lib" -lfoo -lfoo -o "$TMP/main-duplicate" "$TMP/main.o"
"$CPU_READELF" -d "$TMP/main-duplicate" > "$TMP/main-duplicate.dynamic"
[ "`grep -c 'NEEDED' "$TMP/main-duplicate.dynamic"`" -eq 1 ]

# -L order is real link-name search order.  The selected object's SONAME,
# not the requested link name, is recorded.
"$CPU_LD" --shared --soname=libfoo-alt.so.7 \
  -o "$TMP/first/libfoo.so" "$TMP/alt.o"
"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
  -L"$TMP/first" -L"$TMP/root/lib" -lfoo \
  -o "$TMP/main-first" "$TMP/main.o"
"$CPU_READELF" -d "$TMP/main-first" | grep -q 'NEEDED.*\[libfoo-alt.so.7\]'

# The configured system library tree is also used by -l.
cat > "$HOME/.mcpu/etc/mcpu-ld.conf" <<EOC
MCPU_LD_SYSTEM_LIBRARY_PATH = $TMP/root/lib;
EOC
"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
  -lfoo -o "$TMP/main-config" "$TMP/main.o"
"$CPU_READELF" -d "$TMP/main-config" | grep -q 'NEEDED.*\[libfoo.so.1\]'

# A shared object may itself record a direct ABI-v3 dependency.
"$CPU_LD" --shared --soname=libchild.so.1 \
  -lfoo -o "$TMP/libchild.so.1.0.0" "$TMP/bad.o"
"$CPU_READELF" -d "$TMP/libchild.so.1.0.0" > "$TMP/child.dynamic"
grep -q 'SONAME.*\[libchild.so.1\]' "$TMP/child.dynamic"
grep -q 'NEEDED.*\[libfoo.so.1\]' "$TMP/child.dynamic"

# A named dependency must exist and must be a valid ABI-v3 ET_DYN object.
if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \
     -L"$TMP/root/lib" -lmissing -o "$TMP/missing" "$TMP/main.o" \
     >/dev/null 2>&1; then
  echo "missing -l dependency unexpectedly linked" >&2
  exit 1
fi

cp "$TMP/main" "$TMP/root/lib/libexec.so"
if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \
     -L"$TMP/root/lib" -lexec -o "$TMP/from-exec" "$TMP/main.o" \
     >/dev/null 2>&1; then
  echo "ET_EXEC unexpectedly accepted as -l provider" >&2
  exit 1
fi

# Existing file, valid shared object, wrong exports: link must fail before
# producing an executable.
"$CPU_LD" --shared --soname=libbad.so.1 \
  -o "$TMP/root/lib/libbad.so" "$TMP/bad.o"
rm -f "$TMP/no-provider"
if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \
     -L"$TMP/root/lib" -lbad -o "$TMP/no-provider" "$TMP/main.o" \
     >"$TMP/no-provider.out" 2>"$TMP/no-provider.err"; then
  echo "library without required export unexpectedly linked" >&2
  exit 1
fi
grep -q 'undefined symbol not provided by linked libraries: foo' \
  "$TMP/no-provider.err"
[ ! -e "$TMP/no-provider" ]

# ABI-v1 -l searches only for a static archive.  This directory contains
# only libfoo.so, so the static link must fail instead of using ET_DYN.
if "$CPU_LD" -L"$TMP/root/lib" -lfoo -o "$TMP/static" "$TMP/main.o" \
     >/dev/null 2>&1; then
  echo "ABI-v1 unexpectedly selected a shared -l provider" >&2
  exit 1
fi

# 0.2.16 resolves the recorded SONAME at runtime through the same system
# library search policy.  No explicit --ldpreload is required.
[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/main"`" = 42 ]

"$CPU_LD" --help 2>&1 | grep -q -- '-l <name>'

exit 0