-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathbuild.sh
More file actions
executable file
·2830 lines (2532 loc) · 112 KB
/
Copy pathbuild.sh
File metadata and controls
executable file
·2830 lines (2532 loc) · 112 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/sh
# Cross-build a minimal Linux system for ARM Cortex-M4 (MPS2-AN386)
#
# This script produces a self-contained, bootable Linux image targeting the Arm
# MPS2-AN386 FPGA platform (Cortex-M4, no MMU, Thumb-2 only).
# It builds a first-pass GCC cross-compiler (C only), a shared FDPIC libc,
# BusyBox for a minimal userspace, and a Linux kernel with embedded initramfs.
set -e
# shellcheck disable=SC2329
CPU=arm
TARGET=arm-uclinuxfdpiceabi
FLAVOR=cortexm-fdpic
BINUTILS_VERSION=2.46.0
GCC_VERSION=16.1.0
UCLIBC_NG_VERSION=1.0.57
MUSL_VERSION=1.2.5
BUSYBOX_VERSION=1.37.0
LINUX_VERSION=7.0
BINUTILS_URL=https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VERSION}.tar.xz
GCC_URL=https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.xz
# GitHub auto-archive. The canonical mirror at downloads.uclibc-ng.org
# has been observed returning HTTP 522 (Cloudflare-to-origin failure)
# for extended windows; GitHub's tag-based source archive is permanent
# and byte-equivalent to the upstream tarball content (same 5,527-file
# tree, only the top-level directory uses lowercase 'u' which we rename
# back below to keep configs/uClibc-ng-*.config and the rest of this
# script unchanged).
UCLIBC_NG_URL=https://github.com/wbx-github/uclibc-ng/archive/refs/tags/v${UCLIBC_NG_VERSION}.tar.gz
MUSL_URL=https://musl.libc.org/releases/musl-${MUSL_VERSION}.tar.gz
BUSYBOX_URL=https://busybox.net/downloads/busybox-${BUSYBOX_VERSION}.tar.bz2
LINUX_URL=https://www.kernel.org/pub/linux/kernel/v7.x/linux-${LINUX_VERSION}.tar.xz
ROOTDIR=$(cd "$(dirname "$0")" >/dev/null && pwd)
cd "${ROOTDIR}"
TOOLCHAIN=${ROOTDIR}/toolchain
ROOTFS=${ROOTDIR}/rootfs
LOGDIR=${ROOTDIR}/logs
STATE_DIR=${ROOTDIR}/.build-state
QUIET=${QUIET:-0}
LOG_TAIL_LINES=${LOG_TAIL_LINES:-200}
KERNEL_SYSCALL_TABLE=${KERNEL_SYSCALL_TABLE:-}
KERNEL_CONFIG_FRAGMENT=${KERNEL_CONFIG_FRAGMENT:-}
KERNEL_LTO_MODE=${KERNEL_LTO_MODE:-none}
# DWARF policy. The default ('none') matches the production image:
# CONFIG_DEBUG_INFO_NONE=y, addr2line cannot resolve any symbol, and
# scripts/subsystem-rollup.py exits with the documented "DWARF
# missing" code. Set KERNEL_DEBUG_INFO=reduced to ship REDUCED DWARF
# so the diagnostic rollup can attribute symbols to source dirs. The
# deployed Image is stripped of debug sections before bootwrapper
# packing, so this knob only changes vmlinux artifacts and link time.
KERNEL_DEBUG_INFO=${KERNEL_DEBUG_INFO:-none}
KERNEL_REPORT_DIR=${KERNEL_REPORT_DIR:-${ROOTDIR}/profiles/kernel-pgo}
PGO_WORKLOAD_FILE=${PGO_WORKLOAD_FILE:-${ROOTDIR}/configs/pgo-workload.txt}
PGO_BASE_CONFIG_FRAGMENT=${PGO_BASE_CONFIG_FRAGMENT:-${ROOTDIR}/configs/kernel-pgo-prune.config}
# Extra GCC-kernel-LTO link flags for controlled experiments. The local
# CONFIG_LTO_GCC patch forwards this variable only at final link time.
# Keep the default empty; production defaults to no kernel LTO because
# the current pruned image is smaller without it.
KERNEL_LTO_EXTRA_CFLAGS=${KERNEL_LTO_EXTRA_CFLAGS:-}
LIBC_IMPL_EXPLICIT=0
if [ "${LIBC_IMPL+x}" = x ]; then
LIBC_IMPL_EXPLICIT=1
fi
EXPERIMENTAL_MUSL_DEFAULT=${EXPERIMENTAL_MUSL_DEFAULT:-0}
if [ "${LIBC_IMPL_EXPLICIT}" = "0" ]; then
if [ "${EXPERIMENTAL_MUSL_DEFAULT}" = "1" ]; then
LIBC_IMPL=musl
else
LIBC_IMPL=uclibc-ng
fi
fi
# Closest musl-side matches for the size-oriented uClibc-ng config:
# simple allocator, section-friendly codegen, GNU hash-only dynamic
# linker metadata, no legacy time32 compatibility shims, and a
# BusyBox-only source set that drops unused subsystems plus most of
# musl's locale/multibyte/wide-char machinery in favor of tiny
# ASCII/C-locale replacements.
MUSL_MALLOC_DIR=${MUSL_MALLOC_DIR:-oldmalloc}
MUSL_DISABLE_COMPAT_TIME32=${MUSL_DISABLE_COMPAT_TIME32:-1}
# GCC 15 on this target shrinks musl materially with -Oz and
# -fno-semantic-interposition. The latter is safe for this BusyBox-only
# shared-libc profile and reduces internal PIC call overhead/size by
# letting the compiler assume musl's own global definitions are final.
MUSL_EXTRA_CFLAGS=${MUSL_EXTRA_CFLAGS:--Oz -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections -fno-semantic-interposition}
MUSL_EXTRA_LDFLAGS=${MUSL_EXTRA_LDFLAGS:--Wl,--gc-sections -Wl,--hash-style=gnu}
MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL:-1}
MUSL_BUSYBOX_ONLY_NO_TZFILE=${MUSL_BUSYBOX_ONLY_NO_TZFILE:-1}
# Experimental: generate a BusyBox-derived musl export map and relink
# libc against it. This is currently useful as a size-analysis tool, but
# the pruned-export FDPIC runtime is not yet proven bootable enough to be
# the default build path on this target.
MUSL_BUSYBOX_ONLY_EXPORT_MAP=${MUSL_BUSYBOX_ONLY_EXPORT_MAP:-0}
MUSL_BUSYBOX_EXPORT_MAP_PATH=${MUSL_BUSYBOX_EXPORT_MAP_PATH:-${STATE_DIR}/musl-busybox-exports.map}
MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES=${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES:-2}
MUSL_PRUNE_UNUSED_MATH=${MUSL_PRUNE_UNUSED_MATH:-1}
MUSL_KEEP_MATH_SRCS=${MUSL_KEEP_MATH_SRCS:-copysign.c copysignl.c fabs.c fabsl.c fmod.c fmodl.c frexp.c frexpl.c scalbn.c scalbnf.c scalbnl.c}
MUSL_OMIT_SRCS_GLOBS=${MUSL_OMIT_SRCS_GLOBS:-./src/aio/*.c ./src/complex/*.c ./src/crypt/*.c ./src/mq/*.c ./src/locale/*.c ./src/multibyte/*.c ./src/ctype/isw*.c ./src/ctype/tow*.c ./src/ctype/wc*.c ./src/misc/wordexp.c ./src/misc/nftw.c ./src/legacy/ftw.c ./src/time/__map_file.c ./src/regex/regcomp.c ./src/regex/regerror.c ./src/regex/regexec.c ./src/regex/tre-mem.c ./src/stdlib/atof.c ./src/stdlib/strtod.c ./src/stdlib/wcstod.c}
BUSYBOX_ONLY_NO_PRINTF_FLOAT=${BUSYBOX_ONLY_NO_PRINTF_FLOAT:-1}
NCPU=$(grep -c processor /proc/cpuinfo 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)
MAKE_JOBS=${MAKE_JOBS:-${NCPU}}
PATH=${TOOLCHAIN}/bin:${PATH}
mkdir -p "${LOGDIR}" "${STATE_DIR}"
# SHA256 checksums for downloaded source packages.
# Update these when bumping component versions.
# To populate missing checksums: sha256sum downloads/*
CHECKSUM_binutils="binutils-${BINUTILS_VERSION}.tar.xz=d75a94f4d73e7a4086f7513e67e439e8fcdcbb726ffe63f4661744e6256b2cf2"
CHECKSUM_gcc="gcc-${GCC_VERSION}.tar.xz=50efb4d94c3397aff3b0d61a5abd748b4dd31d9d3f2ab7be05b171d36a510f79"
CHECKSUM_uclibc="v${UCLIBC_NG_VERSION}.tar.gz=f49704e0affc75fde9ee4e870c20e53c1d807eca2a4683377b359b8361e84312"
CHECKSUM_musl="musl-${MUSL_VERSION}.tar.gz=a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4"
CHECKSUM_busybox="busybox-${BUSYBOX_VERSION}.tar.bz2=3311dff32e746499f4df0d5df04d7eb396382d7e108bb9250e7b519b837043a4"
CHECKSUM_linux="linux-${LINUX_VERSION}.tar.xz=bb7f6d80b387c757b7d14bb93028fcb90f793c5c0d367736ee815a100b3891f0"
assert_supported_libc() {
case "${LIBC_IMPL}" in
uclibc-ng)
return 0
;;
musl)
return 0
;;
*)
echo "ERROR: unsupported LIBC_IMPL='${LIBC_IMPL}' (expected 'uclibc-ng' or 'musl')" >&2
exit 1
;;
esac
}
libc_config_glob() {
case "${LIBC_IMPL}" in
uclibc-ng) echo "configs/uClibc-ng-*" ;;
musl) echo "configs/musl-*" ;;
*)
echo "ERROR: unsupported LIBC_IMPL='${LIBC_IMPL}' (expected 'uclibc-ng' or 'musl')" >&2
exit 1
;;
esac
}
toolchain_fingerprint() {
LIBC_CONFIGS=$(libc_config_glob)
{
sha256sum build.sh
sha256sum patches/0001-* 2>/dev/null || true
sha256sum ${LIBC_CONFIGS} 2>/dev/null || true
printf 'EXPERIMENTAL_MUSL_DEFAULT=%s\n' "${EXPERIMENTAL_MUSL_DEFAULT}"
printf 'LIBC_IMPL=%s\n' "${LIBC_IMPL}"
if [ "${LIBC_IMPL}" = "musl" ]; then
sha256sum \
patches/0024-musl-* \
patches/0025-musl-* \
patches/0026-musl-* \
patches/0027-musl-* \
patches/0028-musl-* \
patches/0029-musl-* \
patches/0030-musl-* \
patches/0031-musl-* \
patches/0033-musl-* \
patches/0034-musl-* \
patches/0035-musl-* \
patches/0036-musl-* \
patches/0037-musl-* \
patches/0038-musl-* \
patches/0039-musl-* \
patches/0040-musl-* \
support/arm-fdpic-crtreloc.c \
2>/dev/null || true
printf 'MUSL_MALLOC_DIR=%s\n' "${MUSL_MALLOC_DIR}"
printf 'MUSL_DISABLE_COMPAT_TIME32=%s\n' "${MUSL_DISABLE_COMPAT_TIME32}"
printf 'MUSL_EXTRA_CFLAGS=%s\n' "${MUSL_EXTRA_CFLAGS}"
printf 'MUSL_EXTRA_LDFLAGS=%s\n' "${MUSL_EXTRA_LDFLAGS}"
printf 'MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=%s\n' "${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL}"
printf 'MUSL_BUSYBOX_ONLY_NO_TZFILE=%s\n' "${MUSL_BUSYBOX_ONLY_NO_TZFILE}"
printf 'MUSL_BUSYBOX_ONLY_EXPORT_MAP=%s\n' "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}"
printf 'MUSL_PRUNE_UNUSED_MATH=%s\n' "${MUSL_PRUNE_UNUSED_MATH}"
printf 'MUSL_KEEP_MATH_SRCS=%s\n' "${MUSL_KEEP_MATH_SRCS}"
printf 'MUSL_OMIT_SRCS_GLOBS=%s\n' "${MUSL_OMIT_SRCS_GLOBS}"
printf 'BUSYBOX_ONLY_NO_PRINTF_FLOAT=%s\n' "${BUSYBOX_ONLY_NO_PRINTF_FLOAT}"
if [ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ]; then
sha256sum "${MUSL_BUSYBOX_EXPORT_MAP_PATH}"
fi
fi
} | sha256sum | cut -d' ' -f1
}
image_fingerprint() {
{
printf '%s\n' "$1"
printf 'KERNEL_LTO_MODE=%s\n' "${KERNEL_LTO_MODE}"
printf 'KERNEL_LTO_EXTRA_CFLAGS=%s\n' "${KERNEL_LTO_EXTRA_CFLAGS}"
printf 'KERNEL_SYSCALL_TABLE=%s\n' "${KERNEL_SYSCALL_TABLE}"
printf 'KERNEL_CONFIG_FRAGMENT=%s\n' "${KERNEL_CONFIG_FRAGMENT}"
printf 'KERNEL_DEBUG_INFO=%s\n' "${KERNEL_DEBUG_INFO}"
if [ -n "${KERNEL_SYSCALL_TABLE}" ] && [ -f "${KERNEL_SYSCALL_TABLE}" ]; then
sha256sum "${KERNEL_SYSCALL_TABLE}"
fi
if [ -n "${KERNEL_CONFIG_FRAGMENT}" ] && [ -f "${KERNEL_CONFIG_FRAGMENT}" ]; then
sha256sum "${KERNEL_CONFIG_FRAGMENT}"
fi
printf 'PGO_WORKLOAD_FILE=%s\n' "${PGO_WORKLOAD_FILE}"
if [ -f "${PGO_WORKLOAD_FILE}" ]; then
sha256sum "${PGO_WORKLOAD_FILE}"
fi
sha256sum build.sh
find configs patches tools scripts -type f -print0 | sort -z | xargs -0 sha256sum
} | sha256sum | cut -d' ' -f1
}
refresh_build_fingerprints() {
TOOLCHAIN_FP=$(toolchain_fingerprint)
IMAGE_FP=$(image_fingerprint "${TOOLCHAIN_FP}")
}
refresh_build_fingerprints
stage_fingerprint() {
case "$1" in
binutils|gcc|linux_headers|libc)
printf '%s' "${TOOLCHAIN_FP}" ;;
*)
printf '%s' "${IMAGE_FP}" ;;
esac
}
run_logged() {
STEP=$1
shift
if [ "${QUIET}" = "1" ]; then
echo "BUILD: ${CURRENT_STAGE}: ${STEP}"
if "$@" >>"${CURRENT_LOG}" 2>&1; then
return 0
else
STATUS=$?
fi
echo "ERROR: ${CURRENT_STAGE} failed during ${STEP}" >&2
echo "ERROR: showing the last ${LOG_TAIL_LINES} lines from ${CURRENT_LOG}" >&2
tail -n "${LOG_TAIL_LINES}" "${CURRENT_LOG}" >&2 || cat "${CURRENT_LOG}" >&2
exit "${STATUS}"
fi
"$@"
}
extract_source() {
ARCHIVE=$1
SRCDIR=$2
shift 2
if [ -d "${SRCDIR}" ]; then
echo "BUILD: reusing ${SRCDIR}"
return 0
fi
run_logged "extract ${SRCDIR}" tar "$@" "downloads/${ARCHIVE}"
}
stage_stamp_file() {
echo "${STATE_DIR}/$1.stamp"
}
stage_stamp_matches() {
STAMP_FILE=$(stage_stamp_file "$1")
[ -f "${STAMP_FILE}" ] && grep -qx "$(stage_fingerprint "$1")" "${STAMP_FILE}"
}
mark_stage_complete() {
printf '%s\n' "$(stage_fingerprint "$1")" >"$(stage_stamp_file "$1")"
}
stage_verify_binutils() {
[ -x "${TOOLCHAIN}/bin/${TARGET}-ld" ]
}
stage_verify_gcc() {
[ -x "${TOOLCHAIN}/bin/${TARGET}-gcc" ]
}
stage_verify_linux_headers() {
[ -f "${TOOLCHAIN}/${TARGET}/include/linux/types.h" ]
}
stage_verify_libc() {
[ -f "${TOOLCHAIN}/${TARGET}/lib/libc.a" ] || [ -f "${TOOLCHAIN}/${TARGET}/lib/libc.so" ]
}
stage_verify_busybox() {
[ -x "${ROOTFS}/bin/busybox" ]
}
stage_verify_finalize_rootfs() {
[ -x "${ROOTFS}/etc/rc" ] && [ -L "${ROOTFS}/init" ] || return 1
# FDPIC rootfs must contain the dynamic loader and shared libraries
# that busybox was linked against.
READELF=${TOOLCHAIN}/bin/${TARGET}-readelf
[ -x "${READELF}" ] || return 0
INTERP=$(LC_ALL=C "${READELF}" -l "${ROOTFS}/bin/busybox" 2>/dev/null | sed -n 's/.*Requesting program interpreter: \(.*\)]/\1/p')
[ -z "${INTERP}" ] && return 0
[ -e "${ROOTFS}${INTERP}" ] || [ -L "${ROOTFS}${INTERP}" ] || return 1
_needed_libs=$(LC_ALL=C "${READELF}" -d "${ROOTFS}/bin/busybox" 2>/dev/null |
sed -n 's/.*Shared library: \[\(.*\)\]/\1/p')
for needed in ${_needed_libs}; do
[ -e "${ROOTFS}/lib/${needed}" ] || [ -L "${ROOTFS}/lib/${needed}" ] ||
[ -e "${ROOTFS}/usr/lib/${needed}" ] || [ -L "${ROOTFS}/usr/lib/${needed}" ] || return 1
done
}
stage_verify_linux() {
[ -f "${ROOTDIR}/linux-${LINUX_VERSION}/arch/arm/boot/Image" ]
}
stage_verify_bootwrapper() {
[ -f "${ROOTDIR}/bootwrapper/linux.axf" ]
}
stage_verify_kernel_pgo_cycle() {
[ -f "${KERNEL_REPORT_DIR}/cycle/final/selected-candidate.txt" ] &&
[ -f "${KERNEL_REPORT_DIR}/cycle/configs/pgo-kernel.config" ] &&
[ -f "${ROOTDIR}/bootwrapper/linux.axf" ]
}
stage_verify_kernel_syscall_prune_cycle() {
[ -f "${KERNEL_REPORT_DIR}/syscall-prune-cycle/final/selected-candidate.txt" ] &&
[ -f "${KERNEL_REPORT_DIR}/syscall-prune-cycle/configs/syscall-prune.tbl" ] &&
[ -f "${ROOTDIR}/bootwrapper/linux.axf" ]
}
stage_verify_kernel_lto_sweep() {
[ -f "${KERNEL_REPORT_DIR}/lto-sweep/final/summary.txt" ] &&
[ -f "${KERNEL_REPORT_DIR}/lto-sweep/final/candidate-matrix.txt" ]
}
stage_is_current() {
STAGE=$1
VERIFY_FUNC=stage_verify_${STAGE}
if ! stage_stamp_matches "${STAGE}"; then
return 1
fi
"${VERIFY_FUNC}"
}
# Remove stale source/build trees before re-running a stage so that
# cached artifacts (config.status, already-applied patches) cannot
# silently carry over from a previous fingerprint.
stage_clean() {
case "$1" in
binutils) rm -rf "binutils-${BINUTILS_VERSION}" ;;
gcc) rm -rf "gcc-${GCC_VERSION}" ;;
linux_headers) rm -rf "linux-${LINUX_VERSION}" ;; # shared with linux; both extract fresh
libc) rm -rf "uClibc-ng-${UCLIBC_NG_VERSION}" "musl-${MUSL_VERSION}" ;;
busybox) rm -rf "busybox-${BUSYBOX_VERSION}" "${ROOTFS}" ;;
finalize_rootfs) ;; # idempotent; overwrites its outputs
linux) rm -rf "linux-${LINUX_VERSION}" ;;
bootwrapper) rm -rf bootwrapper ;;
kernel_pgo_cycle) rm -rf "${KERNEL_REPORT_DIR}/cycle" ;;
kernel_syscall_prune_cycle) rm -rf "${KERNEL_REPORT_DIR}/syscall-prune-cycle" ;;
kernel_lto_sweep) rm -rf "${KERNEL_REPORT_DIR}/lto-sweep" ;;
esac
}
verify_checksum() {
FILE=$1
EXPECTED=$2
if [ -z "${EXPECTED}" ]; then
return 0
fi
ACTUAL=$(sha256sum "downloads/${FILE}" | cut -d' ' -f1)
if [ "${ACTUAL}" != "${EXPECTED}" ]; then
echo "ERROR: checksum mismatch for ${FILE}"
echo " expected: ${EXPECTED}"
echo " got: ${ACTUAL}"
exit 1
fi
}
fetch_file() {
URL=$1
CHECKSUM_VAR=$2
PACKAGE=$(basename "${URL}")
mkdir -p downloads
if [ ! -f "downloads/${PACKAGE}" ]; then
echo "BUILD: fetching ${PACKAGE}"
if [ "${QUIET}" = "1" ]; then
wget -q -P downloads "${URL}"
else
wget -P downloads "${URL}"
fi
fi
EXPECTED=""
if [ -n "${CHECKSUM_VAR}" ]; then
EXPECTED=$(echo "${CHECKSUM_VAR}" | cut -d= -f2)
fi
verify_checksum "${PACKAGE}" "${EXPECTED}"
}
patch_already_applied() {
PATCH_NAME=$(basename "$1")
case "${PATCH_NAME}" in
0002-*)
grep -q "config NET_SMALL" init/Kconfig &&
grep -q "CONFIG_NET_SMALL" include/net/protocol.h &&
grep -q "CONFIG_NET_SMALL" net/sunrpc/cache.c &&
grep -q "CONFIG_NET_SMALL" net/unix/af_unix.h
;;
0003-*)
grep -q "config MAX_SWAPFILES_SHIFT" init/Kconfig &&
grep -q "CONFIG_MAX_SWAPFILES_SHIFT" include/linux/swap.h &&
grep -q "MAX_SWAPFILES_SHIFT == 0" include/linux/swapops.h
;;
0004-*)
grep -q "config CRC32_TABLES" init/Kconfig &&
grep -q "#ifndef CONFIG_CRC32_TABLES" lib/crc/crc32-main.c
;;
0005-*)
grep -q "config PROC_STRIPPED" fs/proc/Kconfig &&
grep -q "CONFIG_PROC_STRIPPED" fs/locks.c
;;
0006-*)
grep -q "config LTO_GCC" arch/Kconfig &&
[ -f scripts/Makefile.lto ]
;;
0010-*)
# Check for the unique symbols introduced by the patch rather
# than literal `select` lines, which are whitespace-fragile.
grep -q "config UNWINDER_NONE" arch/arm/Kconfig.debug &&
grep -Eq "^[[:space:]]*select[[:space:]]+ARM_UNWIND[[:space:]]+if[[:space:]]+!UNWINDER_NONE[[:space:]]*$" arch/arm/Kconfig
;;
*)
return 1
;;
esac
}
apply_patch_once() {
PATCH_FILE=$1
PATCH_NAME=$(basename "${PATCH_FILE}")
STAMP_DIR=.applied-patches
STAMP_FILE=${STAMP_DIR}/${PATCH_NAME}
mkdir -p "${STAMP_DIR}"
if [ -f "${STAMP_FILE}" ] && patch_already_applied "${PATCH_FILE}"; then
echo "BUILD: skipping ${PATCH_NAME} (stamp verified)"
return 0
fi
if patch -p1 -N --dry-run <"${PATCH_FILE}" >/dev/null 2>&1; then
echo "BUILD: applying ${PATCH_NAME}"
patch -p1 -N <"${PATCH_FILE}"
touch "${STAMP_FILE}"
elif patch_already_applied "${PATCH_FILE}"; then
echo "BUILD: skipping ${PATCH_NAME} (already applied)"
touch "${STAMP_FILE}"
elif patch -p1 -R --dry-run <"${PATCH_FILE}" >/dev/null 2>&1; then
echo "BUILD: skipping ${PATCH_NAME} (already applied)"
touch "${STAMP_FILE}"
else
echo "ERROR: failed to apply ${PATCH_NAME}"
exit 1
fi
}
build_binutils() {
echo "BUILD: building binutils-${BINUTILS_VERSION}"
fetch_file "${BINUTILS_URL}" "${CHECKSUM_binutils}"
extract_source "binutils-${BINUTILS_VERSION}.tar.xz" "binutils-${BINUTILS_VERSION}" -xJf
cd binutils-${BINUTILS_VERSION}
if patch -p1 -R --dry-run <../patches/0001-arm-Do-not-insert-stubs-needing-Arm-code-on-Thumb-on.patch >/dev/null 2>&1; then
run_logged "apply thumb-only binutils patch" patch -p1 -R <../patches/0001-arm-Do-not-insert-stubs-needing-Arm-code-on-Thumb-on.patch
fi
run_logged "configure" ./configure --target=${TARGET} --prefix=${TOOLCHAIN}
run_logged "build" make -j${MAKE_JOBS}
run_logged "install" make install
cd ../
}
build_gcc() {
echo "BUILD: building gcc-${GCC_VERSION}"
fetch_file "${GCC_URL}" "${CHECKSUM_gcc}"
extract_source "gcc-${GCC_VERSION}.tar.xz" "gcc-${GCC_VERSION}" -xJf
cd gcc-${GCC_VERSION}
run_logged "download gcc prerequisites" contrib/download_prerequisites
mkdir -p ${TARGET}
cd ${TARGET}
run_logged "configure" ../configure --target=${TARGET} \
--prefix=${TOOLCHAIN} \
--disable-multilib \
--disable-shared \
--disable-libssp \
--disable-threads \
--disable-libmudflap \
--disable-libgomp \
--disable-libatomic \
--disable-libsanitizer \
--disable-libquadmath \
--disable-libmpx \
--without-headers \
--with-system-zlib \
--with-arch=armv7e-m \
--with-mode=thumb \
--with-float=soft \
--enable-languages=c
run_logged "build" make -j${MAKE_JOBS}
run_logged "install" make install
cd ../..
}
build_linux_headers() {
echo "BUILD: building linux-${LINUX_VERSION} headers"
fetch_file "${LINUX_URL}" "${CHECKSUM_linux}"
extract_source "linux-${LINUX_VERSION}.tar.xz" "linux-${LINUX_VERSION}" -xJf
cd linux-${LINUX_VERSION}
run_logged "defconfig" make ARCH=${CPU} defconfig
run_logged "headers_install" make ARCH=${CPU} headers_install
mkdir -p "${TOOLCHAIN}/${TARGET}"
rm -rf "${TOOLCHAIN}/${TARGET}/include"
cp -a usr/include ${TOOLCHAIN}/${TARGET}/
cd ../
}
build_uclibc_ng() {
echo "BUILD: building uClibc-${UCLIBC_NG_VERSION}"
fetch_file "${UCLIBC_NG_URL}" "${CHECKSUM_uclibc}"
extract_source "v${UCLIBC_NG_VERSION}.tar.gz" "uClibc-ng-${UCLIBC_NG_VERSION}" -xzf
# GitHub source archive unpacks to lowercase 'uclibc-ng-X.Y.Z'; rename
# to the canonical-tarball capitalization so configs/ and stage_clean
# references stay valid. extract_source's own "reuse" check above
# already short-circuits on subsequent runs once the rename has taken.
[ -d "uClibc-ng-${UCLIBC_NG_VERSION}" ] || mv "uclibc-ng-${UCLIBC_NG_VERSION}" "uClibc-ng-${UCLIBC_NG_VERSION}"
cp configs/uClibc-ng-${UCLIBC_NG_VERSION}-${FLAVOR}.config uClibc-ng-${UCLIBC_NG_VERSION}/.config
cd uClibc-ng-${UCLIBC_NG_VERSION}
# FDPIC ldso refresh: descriptor allocator, eager binding, XIP policy
# plus 0022 follow-up that broadens the writable-text gate and
# replaces additive end-address checks with subtraction-based bounds.
for p in ../patches/0021-ldso-arm-fdpic-*.patch ../patches/0022-ldso-arm-fdpic-*.patch; do
[ -f "${p}" ] || continue
apply_patch_once "${p}"
done
TOOLCHAIN_ESCAPED=$(echo ${TOOLCHAIN}/${TARGET} | sed 's/\//\\\//g')
sed -i "s/^KERNEL_HEADERS=.*\$/KERNEL_HEADERS=\"${TOOLCHAIN_ESCAPED}\/include\"/" .config
# Use a target-relative runtime prefix so PT_INTERP inside built ELFs
# references /lib/ld-uClibc.so.0 instead of the host toolchain path.
# Keep development files at the sysroot root because GCC is not
# configured with an extra /usr sysroot suffix for target headers/crt.
sed -i 's/^RUNTIME_PREFIX=.*$/RUNTIME_PREFIX="\/"/' .config
sed -i 's/^DEVEL_PREFIX=.*$/DEVEL_PREFIX="\/"/' .config
run_logged "oldconfig" sh -c "make oldconfig CROSS=${TARGET}- TARGET_ARCH=${CPU} </dev/null"
run_logged "build and install" make -j${MAKE_JOBS} install CROSS=${TARGET}- TARGET_ARCH=${CPU} \
DESTDIR="${TOOLCHAIN}/${TARGET}"
cd ../
}
build_musl() {
echo "BUILD: building musl-${MUSL_VERSION}"
fetch_file "${MUSL_URL}" "${CHECKSUM_musl}"
extract_source "musl-${MUSL_VERSION}.tar.gz" "musl-${MUSL_VERSION}" -xzf
cd musl-${MUSL_VERSION}
apply_patch_once ../patches/0024-musl-arm-fdpic-dynamic-linking.patch
apply_patch_once ../patches/0025-musl-tiny-iconv.patch
apply_patch_once ../patches/0026-musl-allow-omitting-source-globs.patch
apply_patch_once ../patches/0027-musl-busybox-only-c-locale-and-ascii-multibyte.patch
apply_patch_once ../patches/0028-musl-busybox-only-c-locale.patch
apply_patch_once ../patches/0029-musl-busybox-only-disable-runtime-dlfcn.patch
apply_patch_once ../patches/0030-musl-busybox-only-minimal-dlfcn-stubs.patch
apply_patch_once ../patches/0031-musl-busybox-only-no-tzfile.patch
apply_patch_once ../patches/0033-musl-fdpic-dlstart-direct-dls2.patch
apply_patch_once ../patches/0034-musl-arm-fdpic-soft-tp.patch
apply_patch_once ../patches/0035-musl-fdpic-local-funcdesc-got.patch
apply_patch_once ../patches/0036-musl-fdpic-dlstart-handle-rel.patch
apply_patch_once ../patches/0037-musl-fdpic-init-array-fpaddr.patch
apply_patch_once ../patches/0038-musl-fdpic-runtime-relative-laddr.patch
apply_patch_once ../patches/0039-musl-arm-fdpic-xip-aware-loadmap-and-textrel.patch
apply_patch_once ../patches/0040-musl-fdpic-laddr-idempotent.patch
# musl's ARM TLS fast paths assume CP15/kuser helper conventions that
# do not hold on this Cortex-M FDPIC target. Force direct TP reads
# through the working Thumb syscall ABI instead of function-pointer
# or CP15-based helpers.
cat > arch/arm/pthread_arch.h <<'EOF'
#ifdef __FDPIC__
static inline uintptr_t __get_tp()
{
extern hidden uintptr_t __aeabi_read_tp(void);
return __aeabi_read_tp();
}
#elif ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \
|| __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7
static inline uintptr_t __get_tp()
{
uintptr_t tp;
__asm__ ( "mrc p15,0,%0,c13,c0,3" : "=r"(tp) );
return tp;
}
#else
#if __ARM_ARCH_4__ || __ARM_ARCH_4T__ || __ARM_ARCH == 4
#define BLX "mov lr,pc\n\tbx"
#else
#define BLX "blx"
#endif
static inline uintptr_t __get_tp()
{
extern hidden uintptr_t __a_gettp_ptr;
register uintptr_t tp __asm__("r0");
__asm__ ( BLX " %1" : "=r"(tp) : "r"(__a_gettp_ptr) : "cc", "lr" );
return tp;
}
#endif
#define TLS_ABOVE_TP
#define GAP_ABOVE_TP 8
#define MC_PC arm_pc
#ifdef __FDPIC__
#define MC_GOT arm_r9
#define CANCEL_GOT (*(uintptr_t *)((char *)__syscall_cp_asm+sizeof(uintptr_t)))
#endif
EOF
cat > src/thread/arm/__aeabi_read_tp.s <<'EOF'
.syntax unified
.global __aeabi_read_tp
.type __aeabi_read_tp,%function
__aeabi_read_tp:
#if __FDPIC__
push {r7}
mov r7, #0x0f0000
orr r7, r7, #6
svc #0
pop {r7}
bx lr
#else
ldr r0,1f
add r0,r0,pc
ldr r0,[r0]
2: bx r0
.align 2
1: .word __a_gettp_ptr - 2b
#endif
EOF
cat > src/ldso/arm/tlsdesc.S <<'EOF'
.syntax unified
.text
.global __tlsdesc_static
.hidden __tlsdesc_static
.type __tlsdesc_static,%function
__tlsdesc_static:
ldr r0,[r0]
bx lr
.global __tlsdesc_dynamic
.hidden __tlsdesc_dynamic
.type __tlsdesc_dynamic,%function
__tlsdesc_dynamic:
push {r2,r3,ip,lr}
ldr r1,[r0]
ldr r2,[r1,#4]
ldr r1,[r1]
#if __FDPIC__
push {r7}
mov r7, #0x0f0000
orr r7, r7, #6
svc #0
pop {r7}
#elif ((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \
|| __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7
mrc p15,0,r0,c13,c0,3
#else
ldr r0,1f
add r0,r0,pc
ldr r0,[r0]
2:
#if __ARM_ARCH >= 5
blx r0
#else
#if __thumb__
add lr,pc,#1
#else
mov lr,pc
#endif
bx r0
#endif
#endif
ldr r3,[r0,#-4]
ldr ip,[r3,r1,LSL #2]
sub r0,ip,r0
add r0,r0,r2
#if __ARM_ARCH >= 5
pop {r2,r3,ip,pc}
#else
pop {r2,r3,ip,lr}
bx lr
#endif
#if __FDPIC__ || (((__ARM_ARCH_6K__ || __ARM_ARCH_6KZ__ || __ARM_ARCH_6ZK__) && !__thumb__) \
|| __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH >= 7)
#else
.align 2
1: .word __a_gettp_ptr - 2b
#endif
EOF
MUSL_EFFECTIVE_CFLAGS=${MUSL_EXTRA_CFLAGS}
MUSL_EFFECTIVE_LDFLAGS=${MUSL_EXTRA_LDFLAGS}
if [ "${MUSL_BUSYBOX_ONLY_NO_RUNTIME_DL}" = "1" ]; then
MUSL_EFFECTIVE_CFLAGS="${MUSL_EFFECTIVE_CFLAGS} -DMUSL_BUSYBOX_ONLY_NO_RUNTIME_DL=1"
fi
if [ "${MUSL_BUSYBOX_ONLY_NO_TZFILE}" = "1" ]; then
MUSL_EFFECTIVE_CFLAGS="${MUSL_EFFECTIVE_CFLAGS} -DMUSL_BUSYBOX_ONLY_NO_TZFILE=1"
fi
if [ "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}" = "1" ] &&
[ "${MUSL_BUSYBOX_EXPORT_MAP_PASS:-0}" -gt 0 ] &&
[ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ]; then
MUSL_EFFECTIVE_LDFLAGS="${MUSL_EFFECTIVE_LDFLAGS} -Wl,--version-script=${MUSL_BUSYBOX_EXPORT_MAP_PATH}"
fi
MUSL_EFFECTIVE_OMIT_SRCS_GLOBS=${MUSL_OMIT_SRCS_GLOBS}
if [ "${MUSL_PRUNE_UNUSED_MATH}" = "1" ]; then
for math_src in src/math/*.c; do
math_keep=0
for keep_src in ${MUSL_KEEP_MATH_SRCS}; do
if [ "$(basename "${math_src}")" = "${keep_src}" ]; then
math_keep=1
break
fi
done
if [ "${math_keep}" = "0" ]; then
MUSL_EFFECTIVE_OMIT_SRCS_GLOBS="${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS} ./${math_src}"
fi
done
for math_src in src/math/arm/*.c; do
MUSL_EFFECTIVE_OMIT_SRCS_GLOBS="${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS} ./${math_src}"
done
fi
run_logged "configure" env \
CC=${TOOLCHAIN}/bin/${TARGET}-gcc \
AR=${TOOLCHAIN}/bin/${TARGET}-ar \
RANLIB=${TOOLCHAIN}/bin/${TARGET}-ranlib \
./configure --prefix=/ --syslibdir=/lib
if [ "${MUSL_DISABLE_COMPAT_TIME32}" = "1" ]; then
# This build only targets our bundled BusyBox on a modern kernel,
# so we can drop the 32-bit time ABI compatibility shims to save
# space in the shared libc.
run_logged "build" make -j${MAKE_JOBS} \
MALLOC_DIR=${MUSL_MALLOC_DIR} \
STARTFILE_CRT=rcrt1.o \
LDSO_ABI_SUFFIX=-fdpic \
COMPAT_SRC_DIRS= \
"OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \
"CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \
"LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}"
else
run_logged "build" make -j${MAKE_JOBS} \
MALLOC_DIR=${MUSL_MALLOC_DIR} \
STARTFILE_CRT=rcrt1.o \
LDSO_ABI_SUFFIX=-fdpic \
"OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \
"CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \
"LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}"
fi
MUSL_KERNEL_HEADERS_BACKUP=${ROOTDIR}/.musl-kernel-headers
rm -rf "${MUSL_KERNEL_HEADERS_BACKUP}"
mkdir -p "${MUSL_KERNEL_HEADERS_BACKUP}"
for hdr_dir in asm asm-generic drm linux misc mtd rdma scsi sound video xen; do
[ -e "${TOOLCHAIN}/${TARGET}/include/${hdr_dir}" ] || continue
cp -a "${TOOLCHAIN}/${TARGET}/include/${hdr_dir}" "${MUSL_KERNEL_HEADERS_BACKUP}/"
done
rm -rf "${TOOLCHAIN}/${TARGET}/lib"
rm -rf "${TOOLCHAIN}/${TARGET}/include"
if [ "${MUSL_DISABLE_COMPAT_TIME32}" = "1" ]; then
run_logged "install" make \
MALLOC_DIR=${MUSL_MALLOC_DIR} \
STARTFILE_CRT=rcrt1.o \
LDSO_ABI_SUFFIX=-fdpic \
COMPAT_SRC_DIRS= \
"OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \
"CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \
"LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" \
install DESTDIR="${TOOLCHAIN}/${TARGET}"
else
run_logged "install" make \
MALLOC_DIR=${MUSL_MALLOC_DIR} \
STARTFILE_CRT=rcrt1.o \
LDSO_ABI_SUFFIX=-fdpic \
"OMIT_SRCS_GLOBS=${MUSL_EFFECTIVE_OMIT_SRCS_GLOBS}" \
"CFLAGS=${MUSL_EFFECTIVE_CFLAGS}" \
"LDFLAGS=${MUSL_EFFECTIVE_LDFLAGS}" \
install DESTDIR="${TOOLCHAIN}/${TARGET}"
fi
for hdr_dir in asm asm-generic drm linux misc mtd rdma scsi sound video xen; do
[ -e "${MUSL_KERNEL_HEADERS_BACKUP}/${hdr_dir}" ] || continue
cp -a "${MUSL_KERNEL_HEADERS_BACKUP}/${hdr_dir}" "${TOOLCHAIN}/${TARGET}/include/"
done
rm -rf "${MUSL_KERNEL_HEADERS_BACKUP}"
# GCC's arm-uclinuxfdpiceabi FDPIC PIE specs expect musl's shared
# startup object plus a real __self_reloc implementation. Keep
# musl's Scrt1.o and provide an ARM FDPIC crtreloc.o instead of a
# placeholder.
cp lib/Scrt1.o "${TOOLCHAIN}/${TARGET}/lib/Scrt1.o"
ln -sf /lib/libc.so "${TOOLCHAIN}/${TARGET}/lib/ld-musl-arm-fdpic.so.1"
run_logged "build crtreloc" \
"${TOOLCHAIN}/bin/${TARGET}-gcc" -c -fPIE \
-I"${TOOLCHAIN}/${TARGET}/include" \
"${ROOTDIR}/support/arm-fdpic-crtreloc.c" \
-o "${TOOLCHAIN}/${TARGET}/lib/crtreloc.o"
cd ../
}
build_libc() {
assert_supported_libc
case "${LIBC_IMPL}" in
uclibc-ng)
build_uclibc_ng
;;
musl)
build_musl
;;
esac
}
refresh_musl_busybox_export_map() {
MAP_TMP=${STATE_DIR}/musl-busybox-exports.map.new
[ "${LIBC_IMPL}" = "musl" ] || return 0
[ "${MUSL_BUSYBOX_ONLY_EXPORT_MAP}" = "1" ] || return 0
[ -x "${ROOTDIR}/scripts/generate-musl-export-map.sh" ] || return 0
[ -f "${ROOTFS}/bin/busybox" ] || return 0
"${ROOTDIR}/scripts/generate-musl-export-map.sh" \
"${ROOTFS}/bin/busybox" \
"${TOOLCHAIN}/${TARGET}/lib/libc.so" \
"${MAP_TMP}"
if [ -f "${MUSL_BUSYBOX_EXPORT_MAP_PATH}" ] && \
cmp -s "${MAP_TMP}" "${MUSL_BUSYBOX_EXPORT_MAP_PATH}"; then
rm -f "${MAP_TMP}"
return 0
fi
mv "${MAP_TMP}" "${MUSL_BUSYBOX_EXPORT_MAP_PATH}"
MUSL_BUSYBOX_EXPORT_MAP_UPDATED=1
}
build_busybox() {
echo "BUILD: building busybox-${BUSYBOX_VERSION}"
fetch_file "${BUSYBOX_URL}" "${CHECKSUM_busybox}"
extract_source "busybox-${BUSYBOX_VERSION}.tar.bz2" "busybox-${BUSYBOX_VERSION}" -xjf
cp configs/busybox-${BUSYBOX_VERSION}.config busybox-${BUSYBOX_VERSION}/.config
cd busybox-${BUSYBOX_VERSION}
if [ "${LIBC_IMPL}" = "musl" ]; then
apply_patch_once ../patches/0032-busybox-only-disable-float-printf.patch
fi
sed -i 's/# CONFIG_NOMMU is not set/CONFIG_NOMMU=y/' .config
sed -i 's/# CONFIG_PIE is not set/CONFIG_PIE=y/' .config
case "${LIBC_IMPL}" in
uclibc-ng)
BUSYBOX_EXTRA_CFLAGS="--sysroot=${TOOLCHAIN}/${TARGET} -mthumb -march=armv7e-m -ffunction-sections -fdata-sections -fipa-icf -Os"
BUSYBOX_EXTRA_LDFLAGS="-Wl,--gc-sections"
BUSYBOX_EXTRA_LDLIBS=""
;;
musl)
BUSYBOX_EXTRA_CFLAGS="--sysroot=${TOOLCHAIN}/${TARGET} -isystem ${TOOLCHAIN}/${TARGET}/include -mthumb -march=armv7e-m -ffunction-sections -fdata-sections -fipa-icf -Os"
if [ "${BUSYBOX_ONLY_NO_PRINTF_FLOAT}" = "1" ]; then
BUSYBOX_EXTRA_CFLAGS="${BUSYBOX_EXTRA_CFLAGS} -DBUSYBOX_ONLY_NO_PRINTF_FLOAT=1"
fi
BUSYBOX_EXTRA_LDFLAGS="-Wl,--gc-sections -Wl,-dynamic-linker,/lib/ld-musl-arm-fdpic.so.1 -Wl,-rpath-link,${TOOLCHAIN}/${TARGET}/lib -L${TOOLCHAIN}/${TARGET}/lib -B${TOOLCHAIN}/${TARGET}/lib"
BUSYBOX_EXTRA_LDLIBS=""
;;
esac
sed -i "s|CONFIG_EXTRA_CFLAGS=\"\"|CONFIG_EXTRA_CFLAGS=\"${BUSYBOX_EXTRA_CFLAGS}\"|" .config
# With FDPIC PIE userspace, gc-sections strips dead ELF sections before
# the final link while preserving shared-library dynamic linking.
sed -i "s|CONFIG_EXTRA_LDFLAGS=\"\"|CONFIG_EXTRA_LDFLAGS=\"${BUSYBOX_EXTRA_LDFLAGS}\"|" .config
sed -i "s|CONFIG_EXTRA_LDLIBS=\"\"|CONFIG_EXTRA_LDLIBS=\"${BUSYBOX_EXTRA_LDLIBS}\"|" .config
# Reinstall into a clean rootfs so disabled applets do not leave stale links.
rm -rf "${ROOTFS}"
run_logged "oldconfig" make oldconfig
run_logged "build and install" make -j${MAKE_JOBS} CROSS_COMPILE=${TARGET}- CONFIG_PREFIX=${ROOTFS} install SKIP_STRIP=y
cd ../
MUSL_BUSYBOX_EXPORT_MAP_UPDATED=0
refresh_musl_busybox_export_map
if [ "${MUSL_BUSYBOX_EXPORT_MAP_UPDATED}" = "1" ]; then
MUSL_BUSYBOX_EXPORT_MAP_PASS=${MUSL_BUSYBOX_EXPORT_MAP_PASS:-0}
MUSL_BUSYBOX_EXPORT_MAP_PASS=$((MUSL_BUSYBOX_EXPORT_MAP_PASS + 1))
if [ "${MUSL_BUSYBOX_EXPORT_MAP_PASS}" -gt "${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES}" ]; then
echo "ERROR: musl BusyBox export map did not converge after ${MUSL_BUSYBOX_EXPORT_MAP_MAX_PASSES} passes" >&2
exit 1
fi
echo "BUILD: musl export map refreshed from BusyBox (pass ${MUSL_BUSYBOX_EXPORT_MAP_PASS})"
refresh_build_fingerprints
rm -rf "musl-${MUSL_VERSION}" "busybox-${BUSYBOX_VERSION}" "${ROOTFS}"
build_musl
build_busybox
mark_stage_complete libc
return 0
fi
}
copy_runtime_src() {
SRC=$1
# Canonicalize both the sysroot prefix and the source path to defeat
# symlink-based escapes (e.g. ../../outside passing a lexical prefix check).
SYSROOT_REAL=$(cd "${TOOLCHAIN}/${TARGET}" && pwd -P)
SRC_REAL=$(cd "$(dirname "${SRC}")" && pwd -P)/$(basename "${SRC}")
case "${SRC_REAL}" in
"${SYSROOT_REAL}"/*) ;;
*)
echo "ERROR: runtime library '${SRC}' resolves to '${SRC_REAL}', outside ${SYSROOT_REAL}" >&2
exit 1
;;
esac
rel=${SRC#${TOOLCHAIN}/${TARGET}/}
dst_dir=${ROOTFS}/$(dirname "${rel}")
dst=${dst_dir}/$(basename "${SRC}")
mkdir -p "${dst_dir}"
cp -a "${SRC}" "${dst_dir}/"
if [ ! -L "${dst}" ] && [ -x "${TOOLCHAIN}/bin/${TARGET}-strip" ]; then
"${TOOLCHAIN}/bin/${TARGET}-strip" --strip-unneeded "${dst}" >/dev/null 2>&1 || true
fi
if [ -L "${SRC}" ]; then
TARGET_NAME=$(readlink "${SRC}")
case "${TARGET_NAME}" in
/*)
TARGET_SRC=${TOOLCHAIN}/${TARGET}${TARGET_NAME}
;;
*)
TARGET_SRC=$(dirname "${SRC}")/${TARGET_NAME}
;;
esac
[ -e "${TARGET_SRC}" ] || {
echo "ERROR: runtime symlink target '${TARGET_SRC}' does not exist" >&2
exit 1
}
# Guard against circular symlinks: bail if we are about to copy
# the same canonical path we started from.
NEXT_REAL=$(cd "$(dirname "${TARGET_SRC}")" && pwd -P)/$(basename "${TARGET_SRC}")
if [ "${NEXT_REAL}" = "${SRC_REAL}" ]; then
echo "ERROR: circular symlink detected at '${SRC}'" >&2
exit 1
fi
copy_runtime_src "${TARGET_SRC}"
fi
}
copy_runtime_entry() {
NAME=$1
for libdir in "${TOOLCHAIN}/${TARGET}/lib" "${TOOLCHAIN}/${TARGET}/usr/lib"; do
SRC=${libdir}/${NAME}
[ -e "${SRC}" ] || [ -L "${SRC}" ] || continue
copy_runtime_src "${SRC}"
return 0
done
echo "ERROR: failed to locate runtime library '${NAME}' in ${TOOLCHAIN}/${TARGET}" >&2
exit 1