|

Statically Linking C and C++ Programs on Linux with gcc

Before statically linking you C and C++ programs, you should be aware of the drawbacks of the static linking especially with glibc. There are some good discussions already: with glibc you’re linking static programs which are not really static and some others here and here.

That said, you can choose to statically link C and C++ programs on Linux, only when you know what you are doing and why. And you have ways to avoid some problems like setting GCONV_PATH, enabling --enable-static-nss for glibc, using other DNS libraries rather than NSS and never use dlopen. You can even use other libc implementation like uClibc or musl libc which are more friendly for static linking. A comparison of C/POSIX standard library implementations for Linux can be found here.

Linux binaries are not portable if they are built in normal way even with full static linking. However, there are many companies that supply portable Linux binaries that run on a wide range of Linux systems of various versions. Static linking is one of the techniques to build portable binaries. For a detailed explanation of common techniques for building portable binaries, I suggest Creating portable Linux binaries which discusses the “secret sauce”.

One more note: this is not problems from the Linux kernel. Linux kernel keeps very good compatibility. Read Linus’ “WE DO NOT BREAK USERSPACE!” arguments here.

You may wonder why I am talking about static linking. My main motivation is to have memory mapping statically determined and controlled by the program. See the /proc/PID/maps of one statically linked program as follows:

00400000-0060c000 r-xp 00000000 fd:00 920962                             /home/kvplus/think/tmp/runtime/vpc
0080b000-00814000 rwxp 0020b000 fd:00 920962                             /home/kvplus/think/tmp/runtime/vpc
00814000-408a5000 rwxp 00000000 00:00 0 
41652000-41675000 rwxp 00000000 00:00 0                                  [heap]
100000000-800000000 rwxp 00000000 00:00 0 
240000000000-250000000000 rwxs 00000000 ca:11 36                         /mnt/kvplus1-data/pmem-kvplus-0-0
250000000000-260000000000 rwxs 00000000 ca:11 37                         /mnt/kvplus1-data/pmem-kvplus-0-1
260000000000-270000000000 rwxs 00000000 ca:11 38                         /mnt/kvplus1-data/pmem-kvplus-0-2
270000000000-280000000000 rwxs 00000000 ca:11 39                         /mnt/kvplus1-data/pmem-kvplus-0-3
280000000000-290000000000 rwxs 00000000 ca:11 40                         /mnt/kvplus1-data/pmem-kvplus-0-4
290000000000-2a0000000000 rwxs 00000000 ca:11 41                         /mnt/kvplus1-data/pmem-kvplus-0-5
2a0000000000-2b0000000000 rwxs 00000000 ca:11 42                         /mnt/kvplus1-data/pmem-kvplus-0-6
2b0000000000-2c0000000000 rwxs 00000000 ca:11 43                         /mnt/kvplus1-data/pmem-kvplus-0-7
2c0000000000-2d0000000000 rwxs 00000000 ca:11 44                         /mnt/kvplus1-data/pmem-kvplus-0-8
2d0000000000-2e0000000000 rwxs 00000000 ca:11 45                         /mnt/kvplus1-data/pmem-kvplus-0-9
2e0000000000-2f0000000000 rwxs 00000000 ca:11 46                         /mnt/kvplus1-data/pmem-kvplus-0-10
2f0000000000-300000000000 rwxs 00000000 ca:11 47                         /mnt/kvplus1-data/pmem-kvplus-0-11
340000000000-350000000000 rwxs 00000000 ca:11 48                         /mnt/kvplus1-data/pmem-kvplus-0-12
350000000000-360000000000 rwxs 00000000 ca:11 49                         /mnt/kvplus1-data/pmem-kvplus-0-13
360000000000-370000000000 rwxs 00000000 ca:11 50                         /mnt/kvplus1-data/pmem-kvplus-0-14
370000000000-380000000000 rwxs 00000000 ca:11 51                         /mnt/kvplus1-data/pmem-kvplus-0-15
380000000000-390000000000 rwxs 00000000 ca:11 52                         /mnt/kvplus1-data/pmem-kvplus-0-16
390000000000-3a0000000000 rwxs 00000000 ca:11 53                         /mnt/kvplus1-data/pmem-kvplus-0-17
3a0000000000-3b0000000000 rwxs 00000000 ca:11 54                         /mnt/kvplus1-data/pmem-kvplus-0-18
3b0000000000-3c0000000000 rwxs 00000000 ca:11 55                         /mnt/kvplus1-data/pmem-kvplus-0-19
3c0000000000-3d0000000000 rwxs 00000000 ca:11 56                         /mnt/kvplus1-data/pmem-kvplus-0-20
3d0000000000-3e0000000000 rwxs 00000000 ca:11 57                         /mnt/kvplus1-data/pmem-kvplus-0-21
3e0000000000-3f0000000000 rwxs 00000000 ca:11 58                         /mnt/kvplus1-data/pmem-kvplus-0-22
3f0000000000-400000000000 rwxs 00000000 ca:11 59                         /mnt/kvplus1-data/pmem-kvplus-0-23
7fd664000000-7fd664021000 rwxp 00000000 00:00 0 
7fd664021000-7fd668000000 ---p 00000000 00:00 0 
7fd66abb1000-7fd66abb2000 ---p 00000000 00:00 0 
7fd66abb2000-7fd66b5b2000 rwxp 00000000 00:00 0 
7fd66b5b2000-7fd66b5b3000 ---p 00000000 00:00 0 
7fd66b5b3000-7fd66efb8000 rwxp 00000000 00:00 0 
7fd66efb8000-7fd66efb9000 ---p 00000000 00:00 0 
7fd66efb9000-7fd66f9b9000 rwxp 00000000 00:00 0 
7fff054ba000-7fff054cf000 rwxp 00000000 00:00 0                          [stack]
7fff055ff000-7fff05600000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

And a non-statically-linked programs /proc/PID/maps is as follows:

00400000-00406000 r-xp 00000000 fd:00 4115                               /bin/sleep
00605000-00606000 rw-p 00005000 fd:00 4115                               /bin/sleep
0173c000-0175d000 rw-p 00000000 00:00 0                                  [heap]
7f53a7dba000-7f53adbeb000 r--p 00000000 fd:00 133506                     /usr/lib/locale/locale-archive
7f53adbeb000-7f53adc02000 r-xp 00000000 fd:00 1873                       /lib64/libpthread-2.11.2.so
7f53adc02000-7f53ade01000 ---p 00017000 fd:00 1873                       /lib64/libpthread-2.11.2.so
7f53ade01000-7f53ade02000 r--p 00016000 fd:00 1873                       /lib64/libpthread-2.11.2.so
7f53ade02000-7f53ade03000 rw-p 00017000 fd:00 1873                       /lib64/libpthread-2.11.2.so
7f53ade03000-7f53ade07000 rw-p 00000000 00:00 0 
7f53ade07000-7f53adf7a000 r-xp 00000000 fd:00 1849                       /lib64/libc-2.11.2.so
7f53adf7a000-7f53ae179000 ---p 00173000 fd:00 1849                       /lib64/libc-2.11.2.so
7f53ae179000-7f53ae17d000 r--p 00172000 fd:00 1849                       /lib64/libc-2.11.2.so
7f53ae17d000-7f53ae17e000 rw-p 00176000 fd:00 1849                       /lib64/libc-2.11.2.so
7f53ae17e000-7f53ae183000 rw-p 00000000 00:00 0 
7f53ae183000-7f53ae18a000 r-xp 00000000 fd:00 1877                       /lib64/librt-2.11.2.so
7f53ae18a000-7f53ae389000 ---p 00007000 fd:00 1877                       /lib64/librt-2.11.2.so
7f53ae389000-7f53ae38a000 r--p 00006000 fd:00 1877                       /lib64/librt-2.11.2.so
7f53ae38a000-7f53ae38b000 rw-p 00007000 fd:00 1877                       /lib64/librt-2.11.2.so
7f53ae38b000-7f53ae3a9000 r-xp 00000000 fd:00 1842                       /lib64/ld-2.11.2.so
7f53ae5a0000-7f53ae5a3000 rw-p 00000000 00:00 0 
7f53ae5a7000-7f53ae5a8000 rw-p 00000000 00:00 0 
7f53ae5a8000-7f53ae5a9000 r--p 0001d000 fd:00 1842                       /lib64/ld-2.11.2.so
7f53ae5a9000-7f53ae5aa000 rw-p 0001e000 fd:00 1842                       /lib64/ld-2.11.2.so
7f53ae5aa000-7f53ae5ab000 rw-p 00000000 00:00 0 
7fff7fede000-7fff7fef3000 rw-p 00000000 00:00 0                          [stack]
7fff7fffd000-7fff7fffe000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

The mmap from the .so are problems for certain programs.


The following part of this post will introduce how to “statically” link C and C++ programs with gcc on Linux.

Statically link C programs

You should first install the glibc-static package. On Fedora/RHEL/CentOS, you can

# yum install glibc-static

Add the -static as a compilation option to gcc:

$ gcc -static src.c obj.o -o prog

Check whether the compiled binary is statically linked:

$ ldd prog

It should print out:

not a dynamic executable

If you are using some libraries, such as pthread, you should specify these libraries according to their reference order (referrer appears first):

$ gcc -static prog.c -o prog -lpthread

More on the library order in the gcc manual

-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

Statically link C++ programs

First, install the package needed:

# yum install glibc-static libstdc++-static

Under GCC 4.4, you can use the -static option as for C programs:

$ g++ -static

After GCC 4.5, gcc supports the -static-libstdc++ option:

$ gcc -static -static-libstdc++ -static-libgcc

Also note the library order.

After building the program, check whether the program is statically linked as what we do for C programs:

$ ldd cpp-program
not a dynamic executable

Note for CMake: to specify a static library (libssl as an example) in CMake (find more here):

find_library(OPENSSL_LIBRARY libssl.a)

Similar Posts

  • Micosoft招聘部分算法题

    Micosoft招聘部分算法题 1.链表和数组的区别在哪里? 2.编写实现链表排序的一种算法。说明为什么你会选择用这样的方法? 3.编写实现数组排序的一种算法。说明为什么你会选择用这样的方法? 4.请编写能直接实现strstr()函数功能的代码。 5.编写反转字符串的程序,要求优化速度、优化空间。 6.在链表里如何发现循环链接? 7.给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。 8.写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?) 9.给出一个函数来输出一个字符串的所有排列。 10.请编写实现malloc()内存分配函数功能一样的代码。 11.给出一个函数来复制两个字符串A和B。字符串A的后几个字节和字符串B的前几个字节重叠。 12.怎样编写一个程序,把一个有序整数数组放到二叉树中? 13.怎样从顶部开始逐层打印二叉树结点数据?请编程。 14.怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)? 来源:·日月光华 bbs.fudan.edu.cn Read more: Java Calling Native Functions in .DLL on Windows MFC程序使用系统风格界面 OCaml Learning Materials Online Tutorials for Linux Beginners Linux UDP Programming Tutorial Parameterised AngularJS Routing in Asp.net MVC using $routeProvider Getting Process Own Pid in C and…

  • How to `cut` a String Using a String as the Delimiter in Bash?

    Is is possible to cut in Linux using a string as the delimiter? cut –delimiter=”delim” -f 1,3 cut reports: cut: the delimiter must be a single character The most closest solution that I find is using awk/gawk: awk -F ‘delim’ ‘{print $1; print $3}’ From the manual: -F fs –field-separator fs Use fs for the…

  • Chrome’s KDE proxy integration broken on KDE / Fedora

    Chrome reads the proxy settings from Gnome correctly. However, when I run Chrome under KDE, the proxy integration is broken: In the settings of Chrome, clicking the “Change proxy settings” opens the KDE proxy setting dialog correctly (the command kcmshell4 proxy actually is executed). However, after the proxy settings are made, Chrome does not read…

7 Comments

  1. Great article, solves me a problem trying to compile zabbix agent static (fatal error: ac_nonexistent.h: No such file or directory). Thank you!

  2. With cmake, to add the `-static` link option, you may use this piece of code in the CMakeLists.txt file:

    SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static" )

  3. I keep forgetting and remembering linking statically most of the time since I switch between vs and mingw/gnu, but thanks to your explanation finally I can keep tabs on these details. Thanks Eric for these very useful info!

Leave a Reply

Your email address will not be published. Required fields are marked *