You can do the following to get a Y2038 safe buildroot 32-bit ARM system:
- Use the pre-compiled ARM toolchain at https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads. Version 11.2-2022.02 consists of GCC 11.2 and glibc 2.34. (The _TIME_BITS=64 option was introduced in glibc 2.34.)
- Use a Linux kernel with version >= 5.1. https://sourceware.org/pipermail/libc-alpha/2021-August/129718.html says 5.1 is required for full support for 64-bit time.
- There was an attempt to enable system-wide _TIME_BITS=64 in buildroot in https://github.com/buildroot/buildroot/commit/6e33e5908086a511294296f317f6e6f86fa84b1d, but was later reverted in https://github.com/buildroot/buildroot/commit/dd170f0cbad729dba4193b2b20e3de0a7010d485 due to failure to build some packages. What you should still do is to add _TIME_BITS=64 according to the first patch.
- You might get build errors for some packages that undefine _FILE_OFFSET_BITS, in particular the zlib packages, and packages that embed zlib in their code. A simple fix here is to modify the code in these packages to also undef _TIME_BITS whenever _FILE_OFFSET_BITS gets undefined. This seems to work in all cases I have looked at since the affected compilation units do not make use of any time functions anyway.
For example, put this patch as 0002-time-bits.patch in buildroot/package/libzlib/:
--- a/gzguts.h
+++ b/gzguts.h
@@ -9,6 +9,7 @@
# endif
# ifdef _FILE_OFFSET_BITS
# undef _FILE_OFFSET_BITS
+# undef _TIME_BITS
# endif
#endif
This is required because there is an assertion in the glibc headers that error out when _TIME_BITS is 64 but _FILE_OFFSET_BITS is not 64.
UPDATE:
The newly released version 1.3 of zlib includes the patch above (https://github.com/madler/zlib/commit/a566e156b3fa07b566ddbf6801b517a9dba04fa3).
One thing I noticed is that the pre-compiled ARM toolchain that can be downloaded from their website is bundled with Linux Kernel headers from kernel v4.20.13. These old headers are incompatible with _TIME_BITS=64 in some cases, for example the usage of SO_TIMESTAMP/SCM_TIMESTAMP, since these old headers define the incorrect (old) integers. I noticed this while running the btmon logger by seeing corrupt timestamps. I decided to build my own toolchain using updated Linux Kernel headers targeting the Linux Kernel version I'm actually using.
Fortunately, building the toolchain from scratch is relatively straightforward thanks to the automatic build script and the instructions supplied by every release of ARM's toolchain which can be found by clicking the "Release Note" link at the bottom of the relevant download section. The instructions are found under "Building Linux hosted toolchain from sources using Linaro's ABE". The example is for arm-gnu-toolchain-aarch64-none-elf
but the corresponding instructions apply for arm-gnu-toolchain-arm-none-linux-gnueabihf
as well.
In the downloaded manifest file, I changed linux_revision=v4.20.13
to linux_revision=v6.3
(which is my target kernel version) and removed the linux_md5sum
line (I was too lazy to find out the checksum). For some very strange reason, the gcc_stage2_flags
are apparently different in the example manifest compared to the ones used in pre-compiled released binaries. Notably, libatomic is not included due to --disable-libatomic
in the example manifest file. But libatomic is required by many buildroot packages, e.g. ones that need to perform atomic operations on objects larger than 8 bytes, or packages that just happen to link to libatomic.so anyway. To better align with the binary release, I removed --disable-libatomic --without-cloog --without-isl --disable-libgomp --disable-libquadmath
from gcc_stage2_flags
(but did not touch gcc_stage1_flags
).
After replacing the pre-compiled toolchain with this new one, btmon now shows the correct timestamps.