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
|