Skip to content
November 20, 2012 / gus3

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.

Building glibc requires the following packages from Slackware ARM:

  • From a/, aaa_base, gawk, and sed.
  • From ap/, groff and texinfo.
  • From d/, autoconf, automake, binutils-2.22.52.0.2, gcc-4.7, perl, and pkg-config.
  • From l/, libtermcap.

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:

cd /root
mkdir -p slackware{64,arm}-current/source/l/glibc/
mkdir -p tgzstash/{a,l}
mkdir tmp
rsync -aP rsync://ftp.slackware.com/slackware/slackware64-14.1/patches/source/glibc/ slackware64-current/source/glibc/
rsync -aP rsync://ftp.slackware.org.uk/slackwarearm/slackwarearm-14.1/patches/source/glibc/ slackwarearm-current/source/l/glibc/

(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.)

(NOTE 2019-09-12: I have adjusted the rsync source pathnames, to reflect the last released glibc security upgrades for Slackware ARM 14.1. This is the last Slackware ARM release to benefit from glibc built with soft-float.)

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.

As an extra safety step, you may wish to do the following:

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

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

Once you have the minimum downloads in place, type the following:

echo "CFLAGS = -O2 -mfloat-abi=softfp -march=native -mtune=native" > /root/configparms

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:

unset MAKE
screen # w/ extra Enter to make splash screen disappear
cd /root/slackwarearm-current/source/l/glibc
arm/build

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:

cd /root/slackwarearm-current/source/l/glibc
tail -f glibc-2.15-arm-8.build.log

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 (NOTE 2019-09-12: the following checksums are no longer valid):

cd /root/tgzstash/a
mkdir delme
cd delme
explodepkg ../glibc-solibs-2.15-arm-8.tgz
objdump -d lib/incoming/libc-2.15.so | tail | md5sum -
# output: "68d4fbc4059bc14a93efc4980a36bf33 -"
objdump -d lib/incoming/libm-2.15.so | tail | md5sum -
# output: "99dfd015c894c5d94c33e93353bf2c08 -"
# and then "cd .. ; rm -rf delme" if you wish

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:

cd /proc
echo r > sysrq-trigger
echo s > sysrq-trigger
echo e > sysrq-trigger
echo i > sysrq-trigger
echo u > sysrq-trigger

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.

9 Comments

Leave a Comment
  1. Stuart Winter / Nov 21 2012 11:08 am

    Nice article – I was thinking along the lines that rebuilding a few of the packages would suffice to help improve performance on the Pi.

    The Slackware ARM build system predated Slamd64 by several years – not sure where you got that idea from!

    • gus3 / Nov 22 2012 11:46 am

      You’re right, of course. I edited the article.

      Somewhere in the deep recesses of my memory, I already knew that the Slackware ARM project predates Slamd64.

  2. Per Dalén / Feb 28 2013 4:37 am

    What do you think about using hard floating points (-mfloat-abi=hard)? Will it work and is there an advantage to do so? I guess one will need to rebuild most packages to be able to boot.

    • gus3 / Feb 28 2013 3:38 pm

      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.

      (On Slackware ARM, the linker won’t link conflicting ABI’s anyway, as a safety measure.)

      • Per Dalén / Mar 10 2013 6:30 am

        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 :)

  3. br_Orion / Sep 29 2014 9:38 pm

    After i the line arm/build i got this error:

    mkdir: created directory ‘/root/tmp/package-glibc-incoming-tree/usr/man’
    mkdir: created directory ‘/root/tmp/package-glibc-incoming-tree/usr/share’
    mkdir: created directory ‘/root/tmp/build-glibc/kernelheaders/’
    Extracting Linux Kernel headers into /root/tmp/build-glibc
    tar: /root/slackwarearm-current/source/l/glibc/../../d/kernel-headers/sources/kernel-headers-3.16.3.tar.xz: Cannot open: No such file or directory
    tar: Error is not recoverable: exiting now
    glibc-2.19-arm-3.txz.build.log: 3.336:1, 2.398 bits/byte, 70.02% saved, 2829 in, 848 out.

    Maybe the kernel headers are not anymore on that location? Is there anyway to avoid it? because it seems to not be anymore on the slackware tree…

    • br_Orion / Sep 29 2014 10:05 pm

      nevermind, i just added 2 rsync lines to grab the sources

Trackbacks

  1. Links 22/11/2012: New KDE, GNOME 3.x Update | Techrights
  2. SlackwareARM on RaspberryPI and soft/hard float

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.