I know I believe in nothing but it is my sweet nothing.:2022年08月分

2022/08/31(Wed)

[オレオレN6] gcc/binutils/opensslのバージョンが古いのをどうにかしたい

(追記) libc.soをインストールせずにMKSHARED=no MKPROFILE=noをオプションでなくMKPIC=noと一緒に必須にしてlib*.so/lib*_p.a/lib*_pic.aを作らないの方がビルド時間もかからずいいのかな。

そろそろオレオレN6のgccとbinutilsのバージョンを更新しないと困ることが増えてきた、p**srcはデフォルトでgcc(1)のオプションに--stack-protector-strongを指定しやがるしgas(1)が理解できないIntel SHA拡張とか使ってるやつはいるし。 まぁ前者で困るのはpkgtools/cwrapperのビルド時だけでそれ以外はlang/gcc10使えばいいし、後者もmk.confにPREFER.binutilsの設定すりゃよさそうではあるのでなかなか腰が上がらんのだが。

あとopensslもいまだに1.0.2なのでCVE出るたびに1.1.1からバックポートしてるのがめんどくさい、つーか先日コミットログの読み間違いで対策漏れてて大穴空きっぱなしだったりしてな。 こっちもPREFER.openssl設定して外向きのサービスは全部security/opensslをリンクしてるから穴空いてても特に問題はない、ユーザーは全世界で一人だからね。 というか1.0.1から1.0.2でなく飛び越して1.1.1にしときゃ良かったんだが、EOLをよく確認しなかったワイのミスです。1.0.2に上げて半年たたずにEOLになっちゃったよ…

ちなみにNにはgccのアップデートを行うために定義ファイルその他を生成する黒魔術にmknative-gccという仕組がある。 詳しいことはsrc/tools/gcc/README.mknative-gccを読めばいい

…とはいかず、書かれてる手順を実行してもエラーが出てしまう。

まずN6の頃だとドキュメントがメンテされておらずgcc3時代の内容なので、適宜gcc45化の時やN6以降に行われた 修正を念頭に読み替えていく必要があるのだが、それでもうまく動作しない、 何か変だな

ちなみに上手く動かないのは

9. In src/lib, do
   "nbmake-MACHINE dependall install MKGCC=no HAVE_GCC=45".

の部分。

まずsrc/lib以下のビルドを実行するとDESTDIRにlibcがインストールされとらんので、libcに依存する他のライブラリのビルドが止まる。

/usr/obj.alpha/usr/src/tooldir.NetBSD-6.1_STABLE-amd64/bin/alpha--netbsd-gcc  -Wl,-x -shared -Wl,-soname,libBIG5.so.5 -Wl,--warn-shared-textrel  --sysroot=/usr/obj.alpha/usr/src/destdir.alpha   -o libBIG5.so.5.0  -Wl,-rpath,/usr/lib/i18n  -L=/usr/lib/i18n  -Wl,--whole-archive libBIG5_pic.a -Wl,--no-whole-archive
/usr/obj.alpha/usr/src/tooldir.NetBSD-6.1_STABLE-amd64/lib/gcc/alpha--netbsd/4.5.3/../../../../alpha--netbsd/bin/ld: cannot find -lc
collect2: ld returned 1 exit status

*** Failed target:  libBIG5.so.5.0
*** Failed command: /usr/obj.alpha/usr/src/tooldir.NetBSD-6.1_STABLE-amd64/bin/alpha--netbsd-gcc -Wl,-x -shared -Wl,-soname,libBIG5.so.5 -Wl,--warn-shared-textrel --sysroot=/usr/obj.alpha/usr/src/destdir.alpha -o libBIG5.so.5.0 -Wl,-rpath,/usr/lib/i18n -L=/usr/lib/i18n -Wl,--whole-archive libBIG5_pic.a -Wl,--no-whole-archive
*** Error code 1

Stop.

理由は簡単、リンカld(1)が-lcつまりlibcを見つけられませんでしたという話、そもそもlibcはビルドしたけどインストールしてないし当然である。

通常Nのビルドプロセスではライブラリはインストールすることなくリンクが実行される、これはソースツリー内のMakefileでライブラリのリンクにLIBDPLIBSというマクロを使ってるから、以下zlibのリンク(-lz)のサンプル。

LIBDPLIBS+=	z ${NETBSDSRCDIR}/lib/libz

これによって--sysrootオプションに指定されたDESTDIR(src/destdir.MACHINE)よりOBJDIR(src/lib/libz/obj.MACHINE)が優先的にリンカld(1)の検索パス(-Lオプション)に追加される。

##### Libraries that this may depend upon.
.if defined(LIBDPLIBS) && ${MKPIC} != "no"                              # {
.for _lib _dir in ${LIBDPLIBS}
.if !defined(LIBDO.${_lib})
LIBDO.${_lib}!= cd "${_dir}" && ${PRINTOBJDIR}
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.MAKEOVERRIDES+=LIBDO.${_lib}
.endif
.if ${LIBDO.${_lib}} == "_external"
LDADD+=         -l${_lib}
.else
LDADD+=         -L${LIBDO.${_lib}} -l${_lib}
                ^^^^^^^^^^^^^^^^^^
DPADD+=         ${LIBDO.${_lib}}/lib${_lib}.so  # Don't use _LIB_PREFIX
.endif
.endfor
.endif                                                                  # }

これもパッと見複雑だが肝は下線部だけ、詳しくはshare/mk/bsd.READMEを嫁。これによってsrc/lib/libzディレクトリでmake installを実行せずとも-lzのリンクが可能になるわけだ。

今時はmake installでいきなり ステーキルートディレクトリに放り込まれるのでなくDESTDIRに対してになるから、もうこんなめんどくせえトリック必要ないんじゃね?って気がしないでもない。 まぁそれ言い出すとそもそも今時/usr/libって必要?/libだけでいいんじゃねとかUNIX半世紀の総決算が以下略、しょせん我々は 古代遺跡(UCB)から発掘された謎の 巨神(BSD)を訳も分からずこねくり回してるだけなのである、そりゃある日突然 イデ(USL訴訟)が発動して 因果地平(Plan9)の彼方へも飛ばされる。

しかし困ったことにlibcはユーザーがリンクオプションで指定するのではなくld(1)自身が暗黙的に最後にリンクする上にLIBDPLIBSのトリックも使われないので、src/lib/libc/obj.MACHINE以下にlibc.soがあっても知らんがなになる、よってリンクエラーになってるわけ。 ちなみに同じ問題はcsu/crtstuff/libgccでも発生するはずなのだが、それはREADME.mknativeのドキュメント内に

5. In src/lib/csu, do
   "nbmake-MACHINE dependall". and "nbmake-MACHINE install".

6. If the platform sets USE_COMPILERCRTSTUFF=yes, then in
   src/external/gpl3/gcc/lib/crtstuff/ do
   "nbmake-MACHINE obj dependall install"

7. In src/external/gpl3/gcc/lib/libgcc, do
   "nbmake-MACHINE obj includes dependall install".

と手動でインストールしやがれと書いてあるので、DESTDIRにこれらのライブラリがインストール済だから問題は起きない。 つまり手順書にcsu/crtstuff/libgccに加えてlibcも手動でインストールしろって追加しろって事なんやな。

そもそもですねsrc/Makefileに

# Targets invoked by `make build,' in order:
#   (中略)
#   do-lib-csu:      builds and installs prerequisites from lib/csu.
#   do-libgcc:       builds and installs prerequisites from
#                    gnu/lib/crtstuff${LIBGCC_EXT} (if necessary) and
#                    gnu/lib/libgcc${LIBGCC_EXT}.
#   (中略)
#   do-lib-libc:     builds and installs prerequisites from lib/libc.
#   do-lib:          builds and installs prerequisites from lib.

というターゲットがご用意されてるので、こっち使った方が間違いがない気がしないでもない。いちいちUSE_COMPILERCRTSTUFFとか確認しなくていいし。

# cd /usr/src
# nbmake-MACHINE obj do-distrib-dirs includes do-lib-csu HAVE_GCC=45 MKGCC=no MKBINUTILS=no
# nbmake-MACHINE do-libgcc HAVE_GCC=45 MKBINUTILS=no
# nbmake-MACHINE do-lib-libc do-lib HAVE_GCC=45 MKGCC=no MKBINUTILS=no

でいいんじゃねえかなこれ、つーかそもそもmknative-gccごときにlib全体のビルドは不要でlibcとあとせいぜいlibintlだけ(gccのバージョンによってはlibmとlibstdc++もかな)で十分な気がするのだけどまぁ気にしない。

あともうひとつ、do-libターゲット実行中にsrc/external/bsd/atf/lib/libatf++のビルドで止まる、これはlibstdc++とヘッダがインストールされないことが原因。 そもそもmknative-gccの作業にATFとか必要無いからMKATF=noで回避できるけど、MKCXX=noの場合libstdc++依存のライブラリは無視するようMakefile変更する必要あるかもしれない。

そしてもういっちょsrc/tools/binutils以下にもmknative-binutilsというものがあるのだけど、こっちに至ってはドキュメントすらないのである、はぁ…

更にはopensslの更新もめんどくさいのだ、こっちもリンクオプジェクトを羅列したsrc/crypto/external/bsd/openssl/lib/libcrypto/*.inというファイルを大量に更新しないとならん。 これ最初のcommitの時点ではopenssl自身のconfig/Configureスクリプトが自動生成するMakefileからこいつらへと変換するスクリプトが存在したはずなんだけど、今のソースツリーに残ってないのよね。

とはいえ過去のスクリプトが残ってたとしてもopenssl-1.1.1ではこのConfigure周りが大幅に書き直されてて、perlのText::TemplateというテンプレートエンジンでMakefile作るようになってるので多分動かんのよな。 今ではMakefileと一緒にconfigdata.pmというperl moduleが生成されるようになったので、Makefileを読まずともperlスクリプトからビルド情報を読みやすくなったんだけどこれについては後述。

とりあえずopensslのクロスビルドの手順。

$ mkdir build
$ cd build
$ MACHINE=alpha
$ ARCH=alpha
$ OBJDIR=/usr/obj.${MACHINE}
$ TOOLDIR=${OBJDIR}/usr/src/tooldir.NetBSD-6.1_STABLE-amd64
$ export MACHINE ARCH OBJDIR TOOLDIR
$ /usr/src/crypto/external/bsd/openssl/dist/Configure BSD-generic64 AR=${TOOLDIR}/bin/${ARCH}--netbsd-ar AS=${TOOLDIR}/bin/${ARCH}--netbsd-as CC=${TOOLDIR}/bin/${ARCH}--netbsd-gcc CXX=${TOOLDIR}/bin/${ARCH}--netbsd-g++ CPP=${TOOLDIR}/bin/${ARCH}--netbsd-cpp LD=${TOOLDIR}/bin/${ARCH}--netbsd-ld RANLIB=${TOOLDIR}/bin/${ARCH}--netbsd-ranlib CFLAGS="--sysroot=${OBJDIR}/usr/src/destdir.${MACHINE}" LDFLAGS="--sysroot=${OBJDIR}/usr/src/destdir.${MACHINE}"
Configuring OpenSSL version 1.1.1n (0x101010efL) for BSD-generic64
Using os-specific seed configuration
Creating configdata.pm
Creating Makefile

**********************************************************************
***                                                                ***
***   OpenSSL has been successfully configured                     ***
***                                                                ***
***   If you encounter a problem while building, please open an    ***
***   issue on GitHub <https://github.com/openssl/openssl/issues>  ***
***   and include the output from the following command:           ***
***                                                                ***
***       perl configdata.pm --dump                                ***
***                                                                ***
***   (If you are new to OpenSSL, you might want to consult the    ***
***   'Troubleshooting' section in the INSTALL file first)         ***
***                                                                ***
**********************************************************************
$ make
/usr/pkg/bin/perl "-I." -Mconfigdata "util/dofile.pl"  "-oMakefile" include/crypto/bn_conf.h.in > include/crypto/bn_conf.h
/usr/pkg/bin/perl "-I." -Mconfigdata "util/dofile.pl"  "-oMakefile" include/crypto/dso_conf.h.in > include/crypto/dso_conf.h
/usr/pkg/bin/perl "-I." -Mconfigdata "util/dofile.pl"  "-oMakefile" include/openssl/opensslconf.h.in > include/openssl/opensslconf.h
make depend && make _all
...
$ file libcrypto.so.1.1
libcrypto.so.1.1: ELF 64-bit LSB shared object, Alpha (unofficial), version 1 (SYSV), dynamically linked, for NetBSD 6.1, not stripped

configでなくConfigureを実行し、引数にターゲットそしてクロス用のgcc/binutils(AR/AS/CC/CXX/CPP/LD/RANLIB)とCFLAGS/LDFLAGSに--sysrootを指定するだけですな。

上の例ではConfigureのターゲットがBSD-generic64でCPU依存コードは吐かないので、BSD-alphaとかを足してく作業も必要なんやな。

diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf
index 8ca8235ed5..795c400f8b 100644
--- a/Configurations/10-main.conf
+++ b/Configurations/10-main.conf
@@ -995,6 +995,11 @@ my %targets = (
         perlasm_scheme   => "linux64",
     },

+    "BSD-alpha" => {
+        inherit_from     => [ "BSD-generic64", asm("alpha_asm") ],
+        lib_cppflags     => add("-DL_ENDIAN"),
+    },
+
     "bsdi-elf-gcc" => {
         inherit_from     => [ "BASE_unix", asm("x86_elf_asm") ],
         CC               => "gcc",

上を足しただとヘッダファイル足りねえでビルドコケるのでアセンブラソース(を生成するperlスクリプト)も修正いるからまた後日。

なおいま考えてるのと同じ作業がN HEADでopenssl-1.1.1化した時に発生したはずなんだけど、自動生成スクリプトがリポジトリに無いという事は今回も手動で頑張ったんですかね…泥縄だなぁ。

このconfigdata.pmだけど、データ構造が正直あまり筋がよろしくなくMD(機種依存)/MI(機種非依存)がごっちゃに列挙されてるからスクリプト書くのけっこう手間というのはある。

  bn_asm_src => "bn_asm.c alpha-mont.S",
  bn_obj => "bn_asm.o alpha-mont.o",
...
            "crypto/bn" =>
                {
                    "deps" =>
                        [
                            "crypto/bn/alpha-mont.o",
...
                        ],
                    "products" =>
                        {
                            "lib" =>
                                [
                                    "libcrypto",
                                ],
                        },
                },
...
            "crypto/bn/alpha-mont.S" =>
                [
                    "crypto/bn/asm/alpha-mont.pl",
                    "\$(PERLASM_SCHEME)",
                ],
...
            "crypto/bn/alpha-mont.o" =>
                [
                    ".",
                    "include",
                ],
...
            "crypto/bn/alpha-mont.o" =>
                [
                    "crypto/bn/alpha-mont.S",
                ],
...
    "sources" =>
        {
...
            "libcrypto" =>
                [
...
                    "crypto/bn/alpha-mont.o",
...

どのオブジェクトがMIなのかMDなのか判断しづらいのよね、直接Configuration/*.conf読んだ方がいいかもしれない。

話はずれるけどOpenSSL TeamもわざわざText::Template使って自前のMakefile作るくらいならGNU autoconf/automakeでも使えばいいのにという、そんな無駄な工数があるならソースコードの監査とかに労力をですね(禁句)。

そんでNの話をすると、gcc/binutils/opensslもクロス対応のビルドシステム持ってるんだからいちいちNのMakefileに苦労して落とし込む必要もないんだよな。 これOではMakefile.bsd-wrapperというものでconfigureスクリプトをラップすることで無駄な労力を払わないようにする仕組みがあったはず、まぁビルドの並列性は落ちるけど不毛な作業は減らせるよね。

まぁNの場合baseにperl無いからopensslのConfigureは走らせられないけど、でもMKMAINTAINERTOOLS=yesの場合GNU automakeなんかの関係でperlは必要になるはずなんだよね。 実際今pkgsrcでperlを入れずにMKMAINTAINERTOOLS=yesで./build.sh tools実行するとコケるし。

まぁ長々と散文を書いたけど、結論はめんどくさいので当面放置。