5.9. Cocoon Toolchain

The Cocoon toolchain contains the GNU Compiler Collection (GCC), which includes the C and C++ compilers, and Binutils, which includes an assembler and linker.

5.9.1. Installation of the Cocoon Toolchain

Unlike the previous toolchain installation, this toolchain does not need to be bootstrapped. Each component will only be built once.

Unpack the binutils-2.17, gcc-core-4.1.2, and gcc-g++-4.1.2 source packages but do not change directory. Then combine the two packages to the same directory with the following commands:

mv -v gcc-4.1.2/ cocoon-toolchain
mv -v binutils-2.17 cocoon-toolchain/
cd cocoon-toolchain/
ln -vs binutils-2.17/{bfd,binutils,gas,gprof,ld,opcodes} .

This patch is from Binutils CVS: http://sourceware.org/ml/binutils-cvs/2006-06/msg00095.html, and adds the -z lazy option. The vanilla behavior of Binutils is the -z lazy, but later we will make -z now the default for better security. This patch will make it possible to reverse the -z now if needed for debugging reasons. Apply this patch with the following command:

patch -Np1 -i ../binutils-2.17-lazy-1.patch

This is from Binutils CVS: http://sourceware.org/ml/binutils-cvs/2006-10/msg00044.html, and adds support for the mkstemp(3) C library function for safer temporary file creation. Apply this patch with the following command:

patch -Np1 -i ../binutils-2.17-hardened_tmp-3.patch

Patch Binutils for PT_PAX_FLAGS:

cd binutils-2.17/
patch -Np1 -i ../../binutils-2.17-pt_pax-1.patch
cd ../

The following patches have been added to GCC-4.2, in a different way. Apply these patches for uClibc support:

cd binutils-2.17/
patch -Np1 -i ../../binutils-2.17-uClibc_conf-1.patch
cd ../
patch -Np1 -i ../gcc-4.1.2-uClibc_conf-1.patch
patch -Np1 -i ../gcc-4.1.2-uClibc_locale-1.patch

Binutils-2.17 and GCC-4.1.2 do not use Posix compliant command syntax with the head and tail commands. Although this is not critical it should be fixed. Do so with the following commands:

cp -vi libstdc++-v3/configure{,.orig}
sed 's/head -1/head -n 1/g' libstdc++-v3/configure.orig \
    > libstdc++-v3/configure
cp -vi ltcf-c.sh{,.orig}
sed 's/head -1/head -n 1/g' ltcf-c.sh.orig > ltcf-c.sh
cp -vi ltcf-gcj.sh{,.orig}
sed 's/head -1/head -n 1/g' ltcf-gcj.sh.orig > ltcf-gcj.sh
cp -vi configure{,.orig}
sed 's/tail +16c/tail -c +16/g' configure.orig > configure
cp -vi gas/Makefile.in{,.orig}
sed 's/tail +16c/tail -c +16/g' gas/Makefile.in.orig > gas/Makefile.in
cp -vi gcc/Makefile.in{,.orig}
sed 's/tail +16c/tail -c +16/g' gcc/Makefile.in.orig > gcc/Makefile.in
cp -vi gcc/configure{,.orig}
sed 's/tail -3/tail -n 3/g' gcc/configure.orig > gcc/configure
cp -vi ld/testsuite/ld-bootstrap/bootstrap.exp{,.orig}
sed 's/tail +140/tail -n +140/g' \
    ld/testsuite/ld-bootstrap/bootstrap.exp.orig \
      > ld/testsuite/ld-bootstrap/bootstrap.exp

This version of GCC has a small bug/typo with RPATH_ENVVAR value for bfd and opcode. Use the following commands to fix this bug, so that “--enable-shared” will work:

cp -vi Makefile.in{,.orig}
sed -e 's@/.:$$r@/.libs:$$r@' -e 's@/.:@/.libs:@' \
    Makefile.in.orig > Makefile.in

We can change the default behavior of GCC to add various flags by creating a hardened specs header file which redefines GCC spec strings. A detailed summary of the GCC specs is available here: http://developer.apple.com/documentation/developertools/gcc-4.0.1/gcc/Spec-Files.html.

-fstack-protector is passed when _LIBC_REENTRANT is defined (libc does this). -fstack-protector-all is passed on everything else, unless __KERNEL__ is defined (kernel and modules). _FORTIFY_SOURCE only works with optimization, so if no optimization level is set -O is added, unless -D_FORTIFY_SOURCE or D_LIBC_REENTRANT is passed on the command line. FORTIFY_SOURCE redefines functions in Glibc, so much of Glibc can not be built with FORTIFY_SOURCE, hence the _LIBC_REENTRANT condition. These specs add -nonow as an alias for -z lazy because -lazy will not work due to -l* being a library linking option. -z lazy is the vanilla behaviour, -z now is the non-lazy counterpart.

Flags to disable specific options:

-fno-pic -fno-PIC

This will disable 'gcc -fPIC'. If -fpic is used, this will be used instead of -fPIC.

-fno-pie -fno-PIE

This will disable 'gcc -fPIE'. If -fpie is used, this will be used instead of -fPIE.

-fno-stack-protector

This will disable 'gcc -fstack-protector-all'. If -fstack-protector is used, this will be used instead of -fstack-protector-all.

-D_FORTIFY_SOURCE=0

This will disable 'ccp -D_FORTIFY_SOURCE=2'. Any of the -D_FORTIFY_SOURCE="?" options can also be used to redefine -D_FORTIFY_SOURCE.

-O0

This will disable 'gcc -O' optimization needed by -D_FORTIFY_SOURCE=0. Any of the O"?" options can be used to redefine the optimization level.

-nopie

This will disable 'ld -z pie' as well as disable the linking to crtendS.o, Scrt1.o, and crtbeginS.o.

-norelro

This will disable 'ld -z relro' and enable 'ld -z norelro'.

-nocombreloc

This will disable 'ld -z combreloc' and enable 'ld -z nocombreloc'.

-nonow

This will disable 'ld -z now' and enable 'ld -z lazy'.

The following file redefines GCC's default behaviour to add various options:

echo '#ifndef HARDENED_SPECS_H
#define HARDENED_SPECS_H

#if defined(__i386__) && defined(__linux__) && defined(__ELF__) \
        && defined(HAVE_LD_PIE) && defined(TARGET_LIBC_PROVIDES_SSP)

#undef CPP_SPEC
#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT} \
        %{D_FORTIFY_SOURCE*|D_LIBC_REENTRANT:;:-D_FORTIFY_SOURCE=2}"

#undef CC1_SPEC
#define CC1_SPEC "%(cc1_cpu) %{profile:-p} \
        %{D__KERNEL__|fpic|fPIC|fpie|fPIE|fno-pic|fno-PIC \
        :;shared|nostdlib|nostartfiles:-fPIC} \
        %{static|D__KERNEL__|fpic|fPIC|fpie|fPIE|fno-pie|fno-PIE| \
        shared|nostdlib|nostartfiles:;:-fPIE} \
        %{D__KERNEL__|fno-stack-protector|fstack-protector| \
        fstack-protector-all:;D_LIBC_REENTRANT:-fstack-protector;: \
        -fstack-protector-all} %{D_FORTIFY_SOURCE*|D_LIBC_REENTRANT|O*:;:-O}"

#undef CC1PLUS_SPEC
#define CC1PLUS_SPEC \
        "%{D__KERNEL__|fpic|fPIC|fpie|fPIE|fno-pic|fno-PIC \
        :;shared|nostdlib|nostartfiles:-fPIC} \
        %{static|D__KERNEL__|fpic|fPIC|fpie|fPIE|fno-pie|fno-PIE| \
        shared|nostdlib|nostartfiles:;:-fPIE} \
        %{D__KERNEL__|fno-stack-protector|fstack-protector| \
        fstack-protector-all:;D_LIBC_REENTRANT:-fstack-protector;: \
        -fstack-protector-all} %{D_FORTIFY_SOURCE*|D_LIBC_REENTRANT|O*:;:-O}"

#undef ENDFILE_SPEC
#define ENDFILE_SPEC "%{ffast-math|funsafe-math-optimizations: \
        crtfastmath.o%s} \
        %{static|nopie:crtend.o%s;:crtendS.o%s} crtn.o%s"

#undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{shared:;pg|p|profile:gcrt1.o%s; \
        static|nopie:crt1.o%s;:Scrt1.o%s} crti.o%s \
        %{static:crtbeginT.o%s;nopie:crtbegin.o%s;:crtbeginS.o%s}"

#undef LINK_PIE_SPEC
#define LINK_PIE_SPEC "%{pie:-pie} %{!static:%{!Bstatic: \
        %{nonow:-z lazy;:-z now} %{norelro:-z norelro;:-z relro} \
        %{nocombreloc:-z nocombreloc;:-z combreloc} \
        %{shared|Bshareable|i|r|pie|nopie:;:-pie}}}"

#else /* __i386__ && __linux__ && __ELF__ && HAVE_LD_PIE */
#error "You are using an unsupported system. This header can not be used."
#endif /* __i386__ && __linux__ && __ELF__ && HAVE_LD_PIE */
#endif /* HARDENED_SPECS_H */' > gcc/hardened-specs.h

This command includes the hardened-specs header in the right place:

cp -vi gcc/gcc.c{,.orig}
sed '0,/.*config.h can define.*/s//#include "hardened-specs.h"\n&/' \
    gcc/gcc.c.orig > gcc/gcc.c

Make a copy this file so we can use it again in chapter 6:

cp -v gcc/hardened-specs.h /tools

Under normal circumstances the GCC fixincludes script is run in order to fix potentially broken header files. As GCC-4.1.2 and libc have already been installed at this point, and their respective header files are known to not require fixing, the fixincludes script is not required. The script may in fact pollute the build environment by installing fixed headers from the host system into GCC's private include directory. The running of the fixincludes script can be suppressed by issuing the following commands:

cp -vi gcc/Makefile.in{,.orig2}
sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig2 > gcc/Makefile.in

Although we don't use fixincludes we still build it. This is the only place where using --enable-werror-always will cause the build to fail due to a warning that fixincl.x uses string constants longer than what the C standard requires compilers to handle. This is somewhat fixed in GCC-4.2 with the addition of the -Wno-overlength-strings compiler flag. We can supress the -Werror flag for fixincludes with the following sed command:

cp -vi fixincludes/Makefile.in{,.orig}
sed 's/@WERROR@/-Wno-error/' fixincludes/Makefile.in.orig \
    > fixincludes/Makefile.in

Don't build libssp.[a,so] with -fstack-protector[-all]. This library won't be used but will be built and installed:

cp -vi libssp/Makefile.in{,.orig}
sed 's/^AM_CFLAGS =/& -fno-stack-protector/' \
    libssp/Makefile.in.orig > libssp/Makefile.in

Don't build libgcc.[a,so] with -fstack-protector[-all]. libgcc.a is often linked into other static libraries and they will fail to resolve __stack_chk symbols:

cp -vi gcc/Makefile.in{,.orig3}
sed 's/^LIBGCC2_CFLAGS =/& -fno-stack-protector/' \
    gcc/Makefile.in.orig3 > gcc/Makefile.in

Don't build crtbegin[,S,T].o or crtend[,S].o files with -fstack-protector[-all]. These libraries should be devoid of dependencies (including the depenency to libc for SSP functions):

cp -vi gcc/Makefile.in{,.orig4}
sed 's/^CRTSTUFF_CFLAGS =/& -fno-stack-protector/' \
    gcc/Makefile.in.orig4 > gcc/Makefile.in
[Important]

Important

The following two commands are critical in ensuring a successful build. Do not skip them.

The next command adjusts the location of the default dynamic linker so it points to /tools:

cp -v gcc/config/i386/linux.h{,.orig}
sed 's@/lib/ld-linux.so.2@/tools/lib/ld-uClibc.so.0@' \
    gcc/config/i386/linux.h.orig > gcc/config/i386/linux.h

The next command removes /usr/include from GCC's include search path. This ensures only our newly installed headers, in /tools/usr/include, are used.

cp -v gcc/config/linux.h{,.orig}
echo "#undef STANDARD_INCLUDE_DIR
#define STANDARD_INCLUDE_DIR 0" >> gcc/config/linux.h

The GCC documentation recommends building outside of the source directory in a dedicated build/object directory:

mkdir -v ../cocoon-build/
cd ../cocoon-build/

Prepare the toolchain for compilation:

../cocoon-toolchain/configure --prefix=/tools \
    --with-local-prefix=/tools --enable-clocale \
    --enable-shared --enable-threads=posix \
    --enable-__cxa_atexit --enable-languages=c,c++ \
    --with-lib-path=/tools/lib --disable-libstdcxx-pch \
    --enable-checking --disable-werror

The meaning of the configure options:

--enable-clocale

This option enabled C locale support for the C++ libraries. The uclibc locale model will be automatically detected.

--enable-shared

This switch allows the building of libbfd-2.17.so and libopcodes-2.17.so from the Binutils package. This switch is the default in the GCC package and allows the building of libgcc_s.so.1 and libgcc_eh.a.

--enable-threads=posix

This enables C++ exception handling for multi-threaded code.

--enable-__cxa_atexit

This option allows use of __cxa_atexit, rather than atexit, to register C++ destructors for local statics and global objects. This option is essential for fully standards-compliant handling of destructors. It also affects the C++ ABI, and therefore results in C++ shared libraries and C++ programs that are interoperable with other Linux distributions.

--enable-languages=c,c++

This option ensures that both the C and C++ compilers are built. This option is provided by the specs patch.

--with-lib-path=/tools/lib

This tells the configure script to specify the library search path during the compilation of Binutils, resulting in /tools/lib being passed to the linker. This prevents the linker from searching through library directories on the host.

--disable-libstdcxx-pch

Do not build the pre-compiled header (PCH) for libstdc++. It takes up a lot of space, and we have no use for it.

--disable-werror

This switch disables the use of -Werror, because -D_FORTIFY_SOURCE will cause a few compiler warnings.

Compile the toolchain:

make gcc_cv_libc_provides_ssp=yes

Install the toolchain:

make install
[Important]

Important

Confirm the new compiler is defining PIC, SSP, FORTIFY_SOURCE, and OPTIMIZE:

echo | cc -dM -E - | grep -E 'PIC|SSP|FORTIFY|OPTIMIZE'

This should return:

#define __OPTIMIZE__ 1
#define _FORTIFY_SOURCE 2
#define __SSP_ALL__ 2
#define __PIC__ 1

Otherwise something went wrong and you should verify libc was installed to /tools/lib, and reinstall it and this toolchain.

Next, prepare the linker for the “Re-adjusting” phase in the next chapter:

make -C ld clean
make -C ld LIB_PATH=/usr/lib:/lib
make -C ld EXEEXT=-new install-exec-local

Details on this package are located in Section 6.13.2, “Contents of Binutils” and Section 6.13.3, “Contents of GCC.”