System Call Layer¶
Working with glibc
¶
Introduction¶
Why this chapter¶
What is glibc
¶
glibc
is a library which has a lot of functions pre-written for you so that
you do not have to write the code again and again. Also it standardizes the
way you should be writing your code. It wraps a lot of system specific details
and all you need to know is to how to call the particular function, and what to
be expected from the function and what are the return values the function will
give you.
glibc
is the GNU Version of Standard C Library
. All the functions
supported in Standard C Library
can be found there + some added by the
GNU
Todo
Give an example of a function in Standard C and Not in GNU LibC
Todo
Give an example of a function in GLIBC and not in Standard C.
For example: Let us say that we have to find the length of a string. Now this is quite a small code to write and we can write the whole thing ourself, but it is a function which will be used a lot of time accross a lot of products. So the library gives you an implementation of this. As the function is present in the library you can safely assume that the function will work fine because of millions of people have used it and tested it.
For the sake of understanding it better we will now go into the code of the library function and see if its similar to our code.
Also we will make some changes to the code so that it stops working incorrectly and then use it in our programs. This exercise is just a demostration of the following.
- We can read the code of glibc.
- We can compile the code of glibc ourselves and use the newly compiled library.
- We can change the code of glibc.
- We can use the changed code of glibc.
Download, Extract and walk through glibc
¶
Download and extract glibc
¶
The source code of glibc is available at https://ftp.gnu.org/gnu/libc/
. You
can sort the list using Last Modified
to get the latest tar package.
From the page I got the link as https://ftp.gnu.org/gnu/libc/glibc-2.24.tar.xz
.
- Let us download this source, see the following snippet for the exact commands.
$ wget https://ftp.gnu.org/gnu/libc/glibc-2.24.tar.xz
--2017-01-29 07:50:02-- https://ftp.gnu.org/gnu/libc/glibc-2.24.tar.xz
Resolving ftp.gnu.org (ftp.gnu.org)... 208.118.235.20, 2001:4830:134:3::b
Connecting to ftp.gnu.org (ftp.gnu.org)|208.118.235.20|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 13554048 (13M) [application/x-tar]
Saving to: ‘glibc-2.24.tar.xz’
glibc-2.24.tar.xz 100%[==>] 12.93M 709KB/s in 21s
2017-01-29 07:50:26 (622 KB/s) - ‘glibc-2.24.tar.xz’ saved [13554048/13554048]
Extract the code¶
- The downloaded code is a compressed tar file. We need to extract it.
rishi@rishi-VirtualBox:~$ tar -xf glibc-2.24.tar.xz
- This creates a directory names
glibc-2.24
in the folder.
Walkthrough glibc
¶
rishi@rishi-VirtualBox:~$ cd glibc-2.24/
rishi@rishi-VirtualBox:~/glibc-2.24$ ls
abi-tags ChangeLog.3 ChangeLog.old-ports-mips
aclocal.m4 ChangeLog.4 ChangeLog.old-ports-powerpc
argp ChangeLog.5 ChangeLog.old-ports-tile
assert ChangeLog.6 config.h.in
benchtests ChangeLog.7 config.make.in
bits ChangeLog.8 configure
BUGS ChangeLog.9 configure.ac
catgets ChangeLog.old-ports conform
ChangeLog ChangeLog.old-ports-aarch64 CONFORMANCE
ChangeLog.1 ChangeLog.old-ports-aix COPYING
ChangeLog.10 ChangeLog.old-ports-alpha COPYING.LIB
ChangeLog.11 ChangeLog.old-ports-am33 cppflags-iterator.mk
ChangeLog.12 ChangeLog.old-ports-arm crypt
ChangeLog.13 ChangeLog.old-ports-cris csu
ChangeLog.14 ChangeLog.old-ports-hppa ctype
ChangeLog.15 ChangeLog.old-ports-ia64 debug
ChangeLog.16 ChangeLog.old-ports-linux-generic dirent
ChangeLog.17 ChangeLog.old-ports-m68k dlfcn
ChangeLog.2 ChangeLog.old-ports-microblaze elf
extra-lib.mk LICENSES nscd stdio-common
extra-modules.mk locale nss stdlib
gen-locales.mk localedata o-iterator.mk streams
gmon login po string
gnulib mach posix sunrpc
grp Makeconfig PROJECTS sysdeps
gshadow Makefile pwd sysvipc
hesiod Makefile.in README termios
hurd Makerules resolv test-skeleton
iconv malloc resource time
iconvdata manual rt timezone
include math Rules version.h
inet mathvec scripts wcsmbs
INSTALL misc setjmp wctype
intl NAMESPACE shadow WUR-REPORT
io NEWS shlib-versions
libc-abis nis signal
libidn nptl socket
libio nptl_db soft-fp
Some string related code is here
rishi@rishi-VirtualBox:~/glibc-2.24$ ls string/str*
string/stratcliff.c string/strcmp.c string/strerror_l.c string/strncase_l.c string/strrchr.c string/str-two-way.h
string/strcasecmp.c string/strcoll.c string/strfry.c string/strncat.c string/strsep.c string/strverscmp.c
string/strcasecmp_l.c string/strcoll_l.c string/string.h string/strncmp.c string/strsignal.c string/strxfrm.c
string/strcasestr.c string/strcpy.c string/string-inlines.c string/strncpy.c string/strspn.c string/strxfrm_l.c
string/strcat.c string/strcspn.c string/strings.h string/strndup.c string/strstr.c
string/strchr.c string/strdup.c string/strlen.c string/strnlen.c string/strtok.c
string/strchrnul.c string/strerror.c string/strncase.c string/strpbrk.c string/strtok_r.c
Some math related code is here
$ ls math/w_*
math/w_acos.c math/w_atanhf.c math/w_fmodf.c math/w_j1l.c math/w_lgammal_r.c math/w_logf.c math/w_scalblnl.c
math/w_acosf.c math/w_atanhl.c math/w_fmodl.c math/w_jn.c math/w_lgamma_main.c math/w_logl.c math/w_sinh.c
math/w_acosh.c math/w_cosh.c math/w_hypot.c math/w_jnf.c math/w_lgamma_r.c math/w_pow.c math/w_sinhf.c
math/w_acoshf.c math/w_coshf.c math/w_hypotf.c math/w_jnl.c math/w_log10.c math/w_powf.c math/w_sinhl.c
math/w_acoshl.c math/w_coshl.c math/w_hypotl.c math/w_lgamma.c math/w_log10f.c math/w_powl.c math/w_sqrt.c
math/w_acosl.c math/w_exp10.c math/w_ilogb.c math/w_lgamma_compat.c math/w_log10l.c math/w_remainder.c math/w_sqrtf.c
math/w_asin.c math/w_exp10f.c math/w_ilogbf.c math/w_lgamma_compatf.c math/w_log1p.c math/w_remainderf.c math/w_sqrtl.c
math/w_asinf.c math/w_exp10l.c math/w_ilogbl.c math/w_lgamma_compatl.c math/w_log1pf.c math/w_remainderl.c math/w_tgamma.c
math/w_asinl.c math/w_exp2.c math/w_j0.c math/w_lgammaf.c math/w_log1pl.c math/w_scalb.c math/w_tgammaf.c
math/w_atan2.c math/w_exp2f.c math/w_j0f.c math/w_lgammaf_main.c math/w_log2.c math/w_scalbf.c math/w_tgammal.c
math/w_atan2f.c math/w_exp2l.c math/w_j0l.c math/w_lgammaf_r.c math/w_log2f.c math/w_scalbl.c
math/w_atan2l.c math/w_expl.c math/w_j1.c math/w_lgammal.c math/w_log2l.c math/w_scalbln.c
math/w_atanh.c math/w_fmod.c math/w_j1f.c math/w_lgammal_main.c math/w_log.c math/w_scalblnf.c
The header files for the library is here.
$ ls include/
aio.h ctype.h fenv.h grp-merge.h link.h netinet resolv.h spawn.h syscall.h utmp.h
aliases.h des.h fmtmsg.h gshadow.h list.h nl_types.h rounding-mode.h stab.h sysexits.h values.h
alloca.h dirent.h fnmatch.h iconv.h locale.h nss.h rpc stackinfo.h syslog.h wchar.h
argp.h dlfcn.h fpu_control.h ifaddrs.h malloc.h nsswitch.h rpcsvc stap-probe.h tar.h wctype.h
argz.h elf.h ftw.h ifunc-impl-list.h math.h obstack.h sched.h stdc-predef.h termios.h wordexp.h
arpa endian.h gconv.h inline-hashtab.h mcheck.h poll.h scratch_buffer.h stdio_ext.h tgmath.h xlocale.h
assert.h envz.h getopt.h langinfo.h memory.h printf.h search.h stdio.h time.h
atomic.h err.h getopt_int.h libc-internal.h mntent.h programs set-hooks.h stdlib.h ttyent.h
bits errno.h glob.h libc-symbols.h monetary.h protocols setjmp.h string.h uchar.h
byteswap.h error.h gmp.h libgen.h mqueue.h pthread.h sgtty.h strings.h ucontext.h
caller.h execinfo.h gnu libintl.h net pty.h shadow.h stropts.h ulimit.h
complex.h fcntl.h gnu-versions.h libio.h netdb.h pwd.h shlib-compat.h stubs-prologue.h unistd.h
cpio.h features.h grp.h limits.h netgroup.h regex.h signal.h sys utime.h
Walkthrough strlen
¶
Todo
write this section.
Walkthrough div
¶
Todo
write this section.
Walkthrough open
¶
Todo
write this section.
Compiling the code of glibc¶
Generally compling and installing code on Linux system involves the following stages
- Configuring - running
configure
with right options. - Compiling - running
make
with right options. - Install - running
make install
.
Configuring¶
We will get into the glibc-2.24 source directory and run the configure
script. I have intentionally shown the mistakes which happened so that you also understand the small things which needs to be taken care while configuring and compling.
rishi@rishi-VirtualBox:~/glibc-2.24$ ./configure
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for gcc... gcc
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for readelf... readelf
checking for g++... g++
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking whether g++ can link programs... yes
configure: error: you must configure in a separate build directory
- We got an error that we should use a separate directory for running
configure
rishi@rishi-VirtualBox:~/glibc-2.24$ mkdir ../build_glibc
rishi@rishi-VirtualBox:~/glibc-2.24$ cd ../build_glibc/
- Let us now run the configure command.
rishi@rishi-VirtualBox:~/build_glibc$ ../glibc-2.24/configure
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for gcc... gcc
checking for suffix of object files... o
checking version of sed... 4.2.2, ok
checking for gawk... no
>>>>>>>>>>>>>>>>>SNIP<<<<<<<<<<<<<<<<<<<<<<
checking if gcc is sufficient to build libc... yes
checking for nm... nm
configure: error:
*** These critical programs are missing or too old: gawk
*** Check the INSTALL file for required versions.
- The configure step gave errors - let us install
gawk
now.
rishi@rishi-VirtualBox:~/build_glibc$ sudo apt-get install gawk
[sudo] password for rishi:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libsigsegv2
Suggested packages:
gawk-doc
The following NEW packages will be installed:
gawk libsigsegv2
>>>>>>>>>>>>>SNIP<<<<<<<<<<<<<<
Setting up gawk (1:4.1.3+dfsg-0.1) ...
- Check if the command is present.
rishi@rishi-office:~/mydev/publications/system_calls$ which gawk
/usr/bin/gawk
- Let us run configure again
rishi@rishi-VirtualBox:~/build_glibc$ ../glibc-2.24/configure
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for gcc... gcc
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
>>>>>>>>>>SNIP<<<<<<<<<<<<<<<<<<<<<<
running configure fragment for sysdeps/unix/sysv/linux/x86_64
running configure fragment for sysdeps/unix/sysv/linux
checking installed Linux kernel header files... 3.2.0 or later
checking for kernel header at least 2.6.32... ok
*** On GNU/Linux systems the GNU C Library should not be installed into
*** /usr/local since this might make your system totally unusable.
*** We strongly advise to use a different prefix. For details read the FAQ.
*** If you really mean to do this, run configure again using the extra
*** parameter `--disable-sanity-checks`.
- Configure does not want to overwrite the default library and hence we need to give another directory to install the library.
- Let us make a directory and run the configure script.
rishi@rishi-VirtualBox:~/build_glibc$ mkdir ../install_glibc
rishi@rishi-VirtualBox:~/build_glibc$ ../glibc-2.24/configure --prefix=/home/rishi/install_glibc/
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking for gcc... gcc
checking for suffix of object files... o
configure: creating ./config.status
>>>>>>>SNIP<<<<<<<<<<<<
config.status: creating config.make
config.status: creating Makefile
config.status: creating config.h
config.status: executing default commands
- Configure completed
rishi@rishi-VirtualBox:~/build_glibc$ ls
bits config.h config.log config.make config.status Makefile
Compliing¶
- Let us run the
make
command now.
rishi@rishi-VirtualBox:~/build_glibc$ make -j 16
make -r PARALLELMFLAGS="" -C ../glibc-2.24 objdir=`pwd` all
make[1]: Entering directory '/home/rishi/glibc-2.24'
LC_ALL=C gawk -f scripts/sysd-rules.awk > /home/rishi/build_glibc/sysd-rulesT \
rishi@rishi-VirtualBox:~/build_glibc$ ls
bits config.h config.log config.make config.status Makefile
rishi@rishi-VirtualBox:~/build_glibc$
rishi@rishi-VirtualBox:~/build_glibc$
rishi@rishi-VirtualBox:~/build_glibc$
rishi@rishi-VirtualBox:~/build_glibc$ make -j 16
make -r PARALLELMFLAGS="" -C ../glibc-2.24 objdir=`pwd` all
make[1]: Entering directory '/home/rishi/glibc-2.24'
LC_ALL=C gawk -f scripts/sysd-rules.awk > /home/rishi/build_glibc/sysd-rulesT \
>>>>>>>>>>>>>>>>>>>>>SNIP<<<<<<<<<<<<<<<<<<<
gcc -nostdlib -nostartfiles -o /home/rishi/build_glibc/elf/pldd -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both /home/rishi/build_glibc/csu/crt1.o /home/rishi/build_glibc/csu/crti.o `gcc --print-file-name=crtbegin.o` /home/rishi/build_glibc/elf/pldd.o /home/rishi/build_glibc/elf/xmalloc.o -Wl,-dynamic-linker=/home/rishi/install_glibc/lib/ld-linux-x86-64.so.2 -Wl,-rpath-link=/home/rishi/build_glibc:/home/rishi/build_glibc/math:/home/rishi/build_glibc/elf:/home/rishi/build_glibc/dlfcn:/home/rishi/build_glibc/nss:/home/rishi/build_glibc/nis:/home/rishi/build_glibc/rt:/home/rishi/build_glibc/resolv:/home/rishi/build_glibc/crypt:/home/rishi/build_glibc/mathvec:/home/rishi/build_glibc/nptl /home/rishi/build_glibc/libc.so.6 /home/rishi/build_glibc/libc_nonshared.a -Wl,--as-needed /home/rishi/build_glibc/elf/ld.so -Wl,--no-as-needed -lgcc `gcc --print-file-name=crtend.o` /home/rishi/build_glibc/csu/crtn.o
make[2]: Leaving directory '/home/rishi/glibc-2.24/elf'
make[1]: Leaving directory '/home/rishi/glibc-2.24'
- Make runs successfully.
- Let us check the
install_glibc
directory. It has nothing in it.
$ ls ../install_glibc/
- Let us run the
make install
command.
$ make install
LC_ALL=C; export LC_ALL; \
make -r PARALLELMFLAGS="" -C ../glibc-2.24 objdir=`pwd` install
make[1]: Entering directory '/home/rishi/glibc-2.24'
make subdir=csu -C csu ..=../ subdir_lib
make[2]: Entering directory '/home/rishi/glibc-2.24/csu'
make[2]: Leaving directory '/home/rishi/glibc-
>>>>>>>>>>>SNIP<<<<<<<<<<<<<<<
-f /home/rishi/build_glibc/elf/symlink.list
test ! -x /home/rishi/build_glibc/elf/ldconfig || LC_ALL=C \
/home/rishi/build_glibc/elf/ldconfig \
/home/rishi/install_glibc/lib /home/rishi/install_glibc/lib
/home/rishi/build_glibc/elf/ldconfig: Warning: ignoring configuration file that cannot be opened: /home/rishi/install_glibc/etc/ld.so.conf: No such file or directory
make[1]: Leaving directory '/home/rishi/glibc-2.24'
Install¶
- Let us now check the
install_glibc
directory. It has the required files of the new compiled library.
rishi@rishi-VirtualBox:~/build_glibc$ ls ../install_glibc/
bin etc include lib libexec sbin
Using the new library¶
Let us now use the above library to link and run our code. We will add a new
function to the glibc
, change the behaviour of a function in glibc and use the
new function and call the changed function.
This will give us a good understanding of how to compile and link with the new library.
Here is the code for adding some changes to the glibc code. See the file
glibc-2.24/stdlib/div.c
and glibc-2.24/include/stdlib.h
.
Here is the diff
glibc-2.24/stdlib/div.c
¶
- Here we have added a function
my_div
which just returns -1 on invokation and have changed the way the function div behaves. Now when we will pass 99 and 99 to div it will return 100 and 100. Read the default behaviour in the man pages.
$ diff glibc-2.24/stdlib/div.c temp/glibc-2.24/stdlib/div.c
51d50
< #include <stdio.h>
59,64d57
< if (numer == 99 && denom == 99) {
< printf ("\nValues are 99 and 99");
< result.quot = 100;
< result.rem = 100;
< return result;
< }
69,74d61
< }
<
<
< int my_div(void) {
< printf("\n\nCalling my_div() function.");
< return -1;
- Here is the declaration of the new function.
glibc-2.24/stdlib/stdlib.h
¶
$ diff glibc-2.24/stdlib/stdlib.h temp/glibc-2.24/stdlib/stdlib.h
753,754d752
<
< extern int my_div(void);
- Here is the code which calls the functions.
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h>
#include <stdlib.h>
int main () {
div_t result = div(99, 99);
int x = my_div();
printf ("\n\nQuotient %d Remainder %d", result.quot, result.rem);
return 0;
}
|
- Here is the
Makefile
which will be used to compile the program.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | TARGET = div
OBJ = $(TARGET).o
SRC = $(TARGET).c
CC = gcc
CFLAGS = -g
LDFLAGS = -nostdlib -nostartfiles -static
GLIBCDIR = /home/rishi/install_glibc/lib/
STARTFILES = $(GLIBCDIR)/crt1.o $(GLIBCDIR)/crti.o `gcc --print-file-name=crtbegin.o`
ENDFILES = `gcc --print-file-name=crtend.o` $(GLIBCDIR)/crtn.o
LIBGROUP = -Wl,--start-group $(GLIBCDIR)/libc.a -lgcc -lgcc_eh -Wl,--end-group
INCDIR = /home/rishi/install_glibc/include
$(TARGET): $(OBJ)
$(CC) $(LDFLAGS) -o $@ $(STARTFILES) $^ $(LIBGROUP) $(ENDFILES)
$(OBJ): $(SRC)
$(CC) $(CFLAGS) -c $^ -I `gcc --print-file-name=include` -I $(INCDIR)
clean:
rm -f *.o *.~ $(TARGET)
rm test.c.*
rm a.out
# https://stackoverflow.com/questions/10763394/how-to-build-a-c-program-using-a-custom-version-of-glibc-and-static-linking/10772056#10772056
|
- Run the
make
command.
$ make
gcc -g -c div.c -I `gcc --print-file-name=include` -I /home/rishi/install_glibc/include
gcc -nostdlib -nostartfiles -static -o div /home/rishi/install_glibc/lib//crt1.o /home/rishi/install_glibc/lib//crti.o `gcc --print-file-name=crtbegin.o` div.o -Wl,--start-group /home/rishi/install_glibc/lib//libc.a -lgcc -lgcc_eh -Wl,--end-group `gcc --print-file-name=crtend.o` /home/rishi/install_glibc/lib//crtn.o
- Run the statically linked code
$ ./div
Values are 99 and 99
Calling my_div() function.
Quotient 100 Remainder 100
- See the size of the staticically linked code. The huge size is due to static linking. We will now link it dynamically and then see the size.
$ ls -lh div
-rwxrwxr-x 1 rishi rishi 3.3M Jan 29 20:00 div
- Run the dynamically linked code.
Todo
Link it dynamically.
Error
Unable to do it dynamically.
- See the sizes of the files
rishi@rishi-VirtualBox:~/test_code$ ls -l dynamic-test static-test
-rwxrwxr-x 1 rishi rishi 8600 Jan 29 12:13 dynamic-test
-rwxrwxr-x 1 rishi rishi 909048 Jan 29 12:13 static-test
Todo
Link it dynamically.
- Check the file type of the executables.
Todo
correct the following.
rishi@rishi-VirtualBox:~/test_code$ file static-test
static-test: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=866f4fe367915159ae62cc80a0ae614059d67153, not stripped
rishi@rishi-VirtualBox:~/test_code$ file dynamic-test
dynamic-test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /home/rishi/install_glibc/lib/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c0f8ac9a77a879e6adc855333d6bc88c5078ffd3, not stripped
Conclusion¶
In this chapter we have see pretty important things with respect to using glibc. We have see where to find glibc, how to download, extract, make changes and compile the glibc library in your system.
Doing all the steps hands-on will enable you understand the whole workflow more clearly and will thus improve your understanding of systems.
No comments:
Post a Comment