SPO Lab 4 (Part 2) Libc & Multiaarch

In second part of lab 4, I will attempt to build the standard C library or libc.

Glibc

Lets first download version 2.6 from gnu.org page with wget command :

[obelavina@xerxes ~]$ wget . http://ftp.gnu.org/gnu/glibc/glibc-2.26.tar.gz

Unpacking the .tar file :

[obelavina@xerxes ~]$ tar -zxvf glibc-2.26.tar.gz

As with units package, main installation instructions seem to be outlined in INSTALL file.

TL;DR from the libc INSTALL file:

  1. Don’t compile in the source directory ( meaning for /pathto/glibc-2.26 source folder, you need to create a separate /pathto/glibc-build folder)
  2. Run ./configure with –prefix option ( which tells ‘configure’ where you want the GNU C Library installed, you don’t want it to be installed in the default location /usr/local)

Lets run configure script with the required prefix :

../glibc-2.26/configure --prefix=/home/obelavina/glibc-build

Now launch compilation with make command:

make

This took quite some time; libc provides testrun.sh script that can make our .c source look for libc files in the custom build directory

test source.c :

#include <stdio.h>
#include <stdlib.h>

int main () {
   	/* Print 5 random numbers from 0 to 49 */
   	for( i = 0 ; i < n ; i++ ) {
      		printf("%d\n", rand() % 50);
   	}
	return 0;
}
[obelavina@xerxes glibc-build]$ ./testrun.sh /home/obelavina/lab4/source
33
36
27
15
43

Running ./testrun.sh produces expected output, however it is hard to tell if our source was using glibc built in the home directory or one installed on the system. Lets introduce a bug and make rand() not so random :

/* Return a random integer between 0 and RAND_MAX.  */
int
rand (void)
{
 //  return (int) __random ();
        return 0;
}

After re-compiling with make and running source.c I got the following results :

[obelavina@xerxes glibc-build]$ ./testrun.sh /home/obelavina/lab4/source
0
0
0
0
0

Seems like source was using my own version of glibc !

Multi arch

Development of libraries that target multiple architectures requires some sort of functionality that will decide which version of code (or which version of function) to use. You may want to introduce one function for certain kind of CPU (e.g. one that supports NEON) and add different kind of implementation for some older CPUs. GNU implements multi-arch support through so-called indirect functions (or ifunc) which can decide what to choose at link time.

This functionality allows programmers to optimize functions for different CPUs/different architectures. Here’s an example from GCC documentation on how it can be achieved :

  void *my_memcpy (void *dst, const void *src, size_t len)
  {
    ...
  }
  
  static void (*resolve_memcpy (void)) (void)
  {
    return my_memcpy; // we'll just always select this routine
  }

my_memcpy is our custom implementation of GLibc memcpy. Note that its declaration must match the original function. The second function (resolve_memcpy) is our resolver function that returns a pointer to the selected implementation. The snippet below shows the indirect function that needs to be defined in the same translation unit as the resolver function:

      void *memcpy (void *, const void *, size_t)
           __attribute__ ((ifunc ("resolve_memcpy")));

This blogpost can introduce a better example on how to use ifunc features : https://willnewton.name/uncategorized/using-gnu-indirect-functions/

Written on September 30, 2017