About running 32 bit programs on 64 bit Ubuntu and shared libraries

by Markus Bertheau, last updated on February 5th, 2013 Leave a reply »
Quick answer

To run 32-bit programs on 64-bit installations of Ubuntu, install the package ia32-libs:

markus@ubuntu:~$ sudo apt-get install ia32-libs

Long story

I wrote this article to expand your knowledge and understanding of how Linux works. This knowledge should increase your problem solving skills and speed in the area of server administration and command line use. I show how I adapted an installation shell script of a commercial software package, Flash® Media Server, which was written for RedHat Linux, to work on 64-bit Ubuntu Linux. For every symptom that occurs in the process, I explain the problem behind it and how to fix it. The end result is available in Installing Flash® Media Server on Ubuntu Linux.

This article is the first part in a series on the subject. In it I write about running 32 bit programs on 64 bit operating systems and the concept of shared libraries.

The exact versions of the software used in the course are Ubuntu 8.04 LTS 64-Bit Server and Flash® Media Server 3.5.2, if you want to follow along.

32 bits on 64 bits

When you run the original installer you’ll get an error message about the file fmsini not being found:

markus@ubuntu:~$ tar xfz FlashMediaServer3.5.tar.gz
markus@ubuntu:~$ sudo FMS_3_5_2_r654/installFMS
FMS_3_5_2_r654/installFMS: 172: FMS_3_5_2_r654/fmsini: not found

This error message is quite misleading. The file fmsini exists and it’s a 32 bit binary executable:

markus@ubuntu:~$ file FMS_3_5_2_r654/fmsini 
fmsini: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux
2.2.5, dynamically linked (uses shared libs), stripped

Why the error message “not found“?

The message does not refer to the file fmsini. Instead it refers to a helper program that’s needed to run the 32 bit dynamically linked executable fmsini.

Static and dynamic linkage

There are two types of binary executables: statically linked and dynamically linked ones. First about the statically linked ones: When a program wants to call a library function, it refers to it by name. When building the program from source, all library functions used in the program are copied from the library into the program. The program then contains its own code as well as the code of the library functions it uses. Then in the calling places the name is changed to the address of the corresponding function in the program. This process is called linking because it links together the name of a function with the function itself, its implementation. It’s called static, because the link cannot be changed after the program has been built.

Dynamically linked programs work differently: The program also refers to library functions by name. When building the program, two lists are assembled and stored together with the program: a list of which library functions are used in which places, and a list of the libraries that contain the functions used by the program. That’s all for building the program.

Later, at execution time, a special helper program, the so-called dynamic linker, looks in specific places in the file system for each library on the library list and loads it into memory. Now the dynamic linker knows at what memory addresses the library functions are available. It uses the first list to write the correct address in all places that call library functions. Then the dynamically linked program can be run.

Advantages and disadvantages

The biggest disadvantages of statically linked executables stem from the library sharing potential that is not realized. First, programs are bigger and require more space on the hard disk and in memory. That additional space often contains the same library functions over and over again, because they are used in a lot of programs. Second, security or bug fix updates of libraries require the program to be rebuilt from source and redistributed, which can be very costly.

Dynamically linked executables solve these problems: Shared libraries exist in one copy on the hard disk and in one copy in memory. The programs itself are smaller because they don’t contain library code. Libraries can be updated independently of the programs that use them. The programs themselves don’t have to be altered, just restarted.

They solve these problems at a price, though: More infrastructure is needed to support shared libraries: the libraries itself in the right version, and a more sophisticated program loader. In some scenarios this price is too high, and statically linked executables are used. They only need themselves to run and don’t have any dependencies or library compatibility problems.

The dynamic linker

The dynamic linker helper program has a manual page: ld.so(8). ld.so was the name of the dynamic linker in Linux before 1995/96. Now, for 32 bit, the dynamic linker is in the file /lib/ld-linux.so.2; for 64 bit it’s in /lib64/ld-linux-x86-64.so.2. The manual page still has the old name, though.

64 bit Ubuntu Linux has the ability built in to execute 32 bit statically linked programs. The dynamic linker for 32 bit programs though is not installed by default. It’s in the package libc6-i386. After installing that package the file /lib/ld-linux.so.2 exists, and the first step to executing 32 bit dynamically linked executables is done.

Shared libraries

After installing libc6-i386, you’ll get another error message when trying to execute fmsini:

markus@ubuntu:~$ FMS_3_5_2_r654/fmsini
FMS_3_5_2_r654/fmsini: error while loading shared libraries: libstdc++.so.6:
cannot open shared object file: No such file or directory

This is the dynamic linker, trying to load all the libraries in the list and not finding one of them.

Libraries used by dynamically linked executables are called shared libraries. When the dynamic linker finds that a certain library is already loaded, it can refer the new program to use that one instead of loading it again. That way, a library loaded one time is shared among several programs.

Shared libraries come in files that have a .so in their name. so stands for shared object. “Object” just means compiled, binary code.

ldd(1) shows what shared libraries a program needs and where the dynamic linker found these libraries, if it did:

markus@ubuntu:~$ ldd FMS_3_5_2_r654/fmsini
	linux-gate.so.1 =>  (0xf7fc8000)
	libpthread.so.0 => /lib32/libpthread.so.0 (0xf7fa0000)
	libdl.so.2 => /lib32/libdl.so.2 (0xf7f9c000)
	libstdc++.so.6 => not found
	libm.so.6 => /lib32/libm.so.6 (0xf7f75000)
	libgcc_s.so.1 => not found
	libc.so.6 => /lib32/libc.so.6 (0xf7e12000)
	/lib/ld-linux.so.2 (0xf7fc9000)

The dynamic linker looks for the libraries in a number of places – the manual page has all the details on that. The two missing libraries are in the packages lib32stdc++6 and lib32gcc1 respectively.

ldd, by the way, is just a shell script that calls the dynamic linker. Unless told otherwise, the dynamic linker loads all libraries and executes the program. ldd calls it with arguments that tell it to print information about the shared libraries needed by the program.

The majority of programs today are dynamically linked and use shared libraries. The Ubuntu installation comes with over 400 64 bit shared libraries. There’s a package ia32-libs in Ubuntu’s universe repository that contains the most commonly used shared libraries in 32 bit versions. Installing that package will allow many 32 bit programs to run on 64 bit Ubuntu. In particular, it allows the installer of Flash® Media Server to run (but for other reasons it doesn’t function well yet). The Flash® Media Server itself though needs libraries that aren’t in that package. How to solve that will be the topic of a later part in that series.


Feedback is extremely important to me because it gives me clues about what I need to do differently and what to retain in order to reach my goal. My goal is to have this article be interesting and of use to you, as described in the first paragraph. Please don’t hesitate to leave a comment on which passages are written in a way that hinders comprehension, what should have been left out, or what is missing. I’d also like to hear from you if there’s something you liked especially about this article. Thank you. :)


Optional payment

If you found this article useful, maybe it saves you time or money, and you would like to pay for it, have a look at the paying page.



  1. Brandon says:

    Great article, though I had to read a bit to find the two packages I needed to install. But, just what I needed. Thanks!

  2. Charl says:

    Great thanks! You saved my life!

  3. Tim says:

    Running anything 32bit on my 64bit system seems to segfault. And it’s nothing to do with the dynamic libs and wot-not since the same is true for small, static binaries (ldd shows not dynamic). Also, following the above instructions does not get programs working for me, even for a simple ‘Hello world’ … perhaps i’m cursed?

  4. patchsk says:

    very good article for linux beginners. Thanks

  5. koolfy says:

    Excellent article.

    I felt I had to give you feedback so here it is :)

    Very interesting, well explained and useful article.
    Thank you for letting me understand a little better how my system works :)

  6. Jayden says:

    It was really helpful for the problem I have had so far in setup Android development environment. Thanks again!

  7. Frankwa says:

    Great! Thanks!

  8. dproc says:

    very useful for me. thanks man

  9. dantux says:

    You have one of the best talents on teaching about linux. I really like the way you do it. Please continue with any topics. This one was an eye opener :)

  10. Nevim says:

    You, sir, are a lifesaver!

  11. arham says:

    I found the solutoin before reading the article but it gave me explanation for that.

  12. Dmitry says:

    Thank you!

  13. Bobby says:

    Excellent, detailed, and through article. Saved me a lot of headache. Thank you very much!

© 2018 Markus Bertheau. All rights reserved.