HOWTO: Rebuild Glibc on Slackware ARM 14.0 for the Raspberry Pi

I run Slackware ARM on my Raspberry Pi. I’ve been a longtime fan of Slackware, which caters to my inner control-freak. However, since Slackware ARM (formerly ARMedSlack) is designed to run on a variety of ARM-based systems, and an ARM-based system is typically a System-on-Chip, this means that Slackware ARM is built for maximum compatibility… and minimum optimization. For example, not all ARM CPU’s have on-board floating-point capability. By assuming no floating-point capability, Slackware ARM can run on a wider range of ARM-based systems. However, this can reduce performance significantly.

This guide will explain how to rebuild core glibc libraries to use the greater capability of the Raspberry Pi’s on-board ARM 1176JZF-S CPU. The process is not terribly involved, but using NFS for the build space took 8-1/2 hours, even with the CPU overclocked to 900 MHz.

Prerequisites

N.B.: The following instructions are intended for a root user, with full privileges to do a lot of damage to the system.

All the packages except gcc are checked by the build script before unpacking the glibc source tarball. If you have installed all the packages under a/, ap/, d/, and l/, you should have no problems.

You might also wish to install ap/screen, so you do not have to stay logged in during the build, and n/rsync, which will simplify the download process considerably.

The Slackware ARM build process is a somewhat hybrid affair, drawing from both Slamd64 and core Slackware. Because of this,You will need to install slackkit. (Edit: but not because of any influence from Slamd64. Sorry about that, Mr. Winter.)

The Slackware ARM build files do not include the actual sources for most packages (including glibc), instead relying on the sources from Slackware64. The following will download the minimum files for the build process:

(Note: the above originally omitted the a/ and l/ directories after tgzstash/, which results in an error. I had mistakenly left these sub-directories in place when I was developing these instructions. Thanks to frushiyama for the report, and Stuart Winter for recognizing the culprit.)

The primary configuration file for the slackkit packages is in /usr/share/slackdev/slackdev.config, which assumes the build directories are all under /root. If you move them somewhere else, be sure to adjust the slackdev.config file appropriately. The /root/tgzstash directory should contain subdirectories named a/ and l/, to receive the static object libraries and the regular system libraries, respectively.

On my setup, these working directories are NFS mounts, but they do not have to be. If you use NFS for these mount points, the NFS server needs to have appropriate “no_root_squash” options in the /etc/exports file. I don’t suggest that you use the Raspberry Pi’s SD card for these directories, because the build process will involve a lot of I/O and a lot of SD card wear. An external USB drive or network mount will probably be much easier on your equipment, and possibly faster as well.

If something goes wrong while installing custom packages, you will be able to use another computer to move these files back into their original directories. (In the failure recovery phase, I assume you have already done this.)

The process

Be careful to include a space on each side of the first equals sign. The “configparms” file can modify certain aspects of the glibc build process, once it’s in the build directory. Saving it to a file in /root is a time-saver, in case something goes wrong with the build process later.

Once you have these files in place, type (don’t copy/paste) the following:

This begins the build process, but there’s one more thing to do: put the “configparms” file in place. Watch for the message saying, “Unpacking main glibc source…” When you see this, type Ctrl-Z to suspend the unpacking, then type:

cp /root/configparms /root/tmp/build-glibc/glibc-2.15/
fg

The “cp” command is what will make this a customized build of glibc. The “configparms” file in the glibc source root directory is the official way to modify the Makefile variables. In this case, we’re modifying the CFLAGS variable to detect the CPU model and submodel, and optimize the code for it. The ARM 1176JZF-S is detected automatically by GCC (I checked the source), so the machine code will use more capabilities of the on-board ARM, in a more efficient manner, than the generic code in Slackware ARM.

The wait…

It’s a long process. Expect to wait at least 8 hours, unless you have an Raspberry Pi build farm on your network. It’s the kind of thing you want to let run while you sleep, or work, or read random articles on Wikipedia. If you don’t want to leave your login active, you may type Ctrl-A D to detach from the running “screen” session, then logout as usual. The build will continue running.

If you wish to check the build process occasionally, you can login as root on the Raspberry Pi, then check the build log with the following:

The output of the build session is logged to this file on-the-fly. When the long “gcc” commands scroll by regularly, you can terminate the “tail” command with Ctrl-C, then examine the compilation options in use. You should see the text “-march=native” somewhere in the command line (or look for “mtune” instead). This shows that the “configparms” file was found and put into effect, and the glibc build is producing optimized code for the Raspberry Pi.

If the “tail” command above fails, then the file doesn’t exist, meaning the build has completed, and the build log is compressed into a .bz2 file.

An optional sanity check

If all goes well, you should end up with five new files under /root/tgzstash:

a/glibc-solibs-2.15-arm-8.tgz

a/glibc-zoneinfo-2012f_2012f-noarch-8.tgz

l/glibc-2.15-arm-8.tgz

l/glibc-i18n-2.15-arm-8.tgz

l/glibc-profile-2.15-arm-8.tgz

If you would like to do a quick check that your files were built the same way mine were, you can do the following:

I got these same checksums from two different builds, so if you see the same output, chances are good that you have built the same libraries. The checksums of the individual package files won’t be the same, due to different timestamps of the library files.

If you did not get the same checksums, you may have a different version of GCC or binutils installed. It does not mean that your custom glibc will crash your system, but neither can you assume that a completed build means a usable library. If you got different checksums, proceed at your own risk!

Installation

If you are satisfied with the state of the packages you’ve built, then it’s time to install them:

cd ~/tgzstash
upgradepkg --install-new {a,l}/glibc-*.tgz

You won’t see the normal package descriptions, as there are no corresponding glibc-*.txt files. However, you should see the list of files being removed for replacement. The list of files in i18n and zoneinfo is particularly long. If you get back to a command prompt without seeing any fatal errors from the upgradepkg sub-processes, then your custom glibc is in place and running. Congratulations!

If the upgrade crashes the system

However, if you suddenly begin seeing nothing but error messages, it means your build of glibc is defective. Once the upgradepkg program exits, you will still have a shell, and its internal capabilities, but external commands are no longer available, including “halt” and “shutdown”. If you want to list files in a directory, you will need “echo *”, since “ls” will also be out-of-reach. Very few external programs will be runnable, due to the defective or missing /lib/libc-2.15.so. The only available programs will be statically-linked binaries, and Bash scripts capable of being sourced, which also return no value.

To avoid write errors to the SD card, the best first thing to do is the following:

This is the famous Raising Skinny Elephants mnemonic, but omitting the last step of re-booting the system. Once the OK light stops flashing, I/O to the SD card has stopped, and it’s safe to cut power to the RPi.

With the SD card in another system, “cd” to its mount point, then type the following:

cp root/lib-backup/* lib/
cp root/pkgfile-backup/* var/log/packages/

This will restore both the original libraries in /lib, and their Slackware package files. You should then have a system which is capable of booting. Unmount the SD card (“eject” in Gnome desktop parlance), return it to the RPi, and plug in the power. If Slackware ARM boots OK, you may wish to restore the original packages as an extra precaution before proceeding further, using “upgradepkg –reinstall” as the command.

Conclusion

Building an optimized glibc package on Slackware is not difficult; it’s only a matter of timing the script interruptions. Even though the individual performance improvements may be small, the overall impact on system performance will add up. The libc library is used by nearly every Linux binary, so good optimization can yield both faster execution and less memory pressure.

I have been using optimized glibc packages for nearly 3 weeks, with no signs of problems with stock Slackware ARM programs.

That wouldn’t work for Slackware ARM. The floating-point arguments are passed differently for “soft” and “hard” ABI’s. Slackware ARM uses “soft”, but allows the extension “softfp” so that a function may use the FPU, but floating-point arguments are still passed on the stack.

The “hard” float ABI uses FPU registers to pass floating-point arguments, so a library compiled with “hard” would be looking in the FPU for arguments that got passed on the stack instead. Result: instant segfault. A library used nearly globally, like glibc, compiled with the “hard” ABI would crash every program that tried to launch.

Thanks for the answer and your HOWTO. It made me want to test Slackware for Raspberry using hard float.
I have started to rebuild all important/necessarily packages with the flags “-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard”. I’m using Raspbian “wheezy” as a starting point to build the packages (added some slackware tools to Raspbian).
I have only got 15 packages build yet, so I guess it will take me a while :)