views:

106

answers:

3

I am trying to understand the following behavior of shared libraries in C

Machine One

$ cat one.c 
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc one.c -o one -O3
$ ldd one
    linux-gate.so.1 =>  (0x00331000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00bc2000)
    /lib/ld-linux.so.2 (0x006dc000)
$ cat two.c 
int main() {
    int i = 0;
}
$ gcc two.c -o two -O3
$ ldd two
    linux-gate.so.1 =>  (0x006f7000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
    /lib/ld-linux.so.2 (0x00eb0000)
$

Machine Two

$ cat three.c
#include<stdio.h>

int main() {
    printf ("%d", 45);
}
$ gcc three.c -o three -O3
$ ldd three
    /usr/lib/libcwait.so (0xb7ffd000)
    libc.so.6 => /lib/tls/i686/nosegneg/libc.so.6 (0x002de000)
    /lib/ld-linux.so.2 (0x002bf000)
$

A few things I don't fully understand at present:

  • What does the address given in brackets (for example, (0x002de000)) mean?

    These addresses are different even for the same library on the same machine, which suggests these are addresses of the locations in memory where these libraries are loaded. But, if that is true, why are these libraries loaded in memory at all (I did not execute the programs yet, shouldn't they be loaded only at runtime?).

  • Why does two need any libraries at all? I have used -O3, and the assembler output is

    $ gcc two.c -S -O3 
    $ cat two.s
        .file   "two.c"
        .text
        .p2align 4,,15
    .globl main
        .type   main, @function
    main:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section    .note.GNU-stack,"",@progbits
    $
    

    What is the need of any libraries at all?

  • On Machine Two, why is /usr/lib/libcwait.so being used instead of linux-gate.so.1?

    I think this is because the kernel on Machine Two is very old (2.6.9) and the library linux-gate.so.1 is not available. Is that the reason?

+1  A: 

The number is the memory address where the library is loaded when the executable is run. It is determined at link time and is usually randomized in order to make library function addresses unpredictable and thus more difficult to use in exploits. The standard C library is linked by default by GCC. libcwait is probably another default library, possibly used by older GCC versions.

Gintautas Miliauskas
+2  A: 

The addresses are basically random numbers. Before secure implementations were devised, ldd would consistently indicate the memory addresses where the program sections were loaded. Since about five years ago, many flavors of Linux now intentionally randomize load addresses to frustrate would-be virus writers, etc. I compiled one.c (as t.c) and repeatedly executed ldd:

[wally@zenetfedora .bin]$ cat t.c
#include <stdio.h>
int main()
{
    printf ("%d", 45);
}
[wally@zenetfedora .bin]$ gcc -o t t.c -O3
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x009e5000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00b8d000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00238000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x002a0000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00f93000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00c7a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d1a000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)
[wally@zenetfedora .bin]$ ldd t
    linux-gate.so.1 =>  (0x00d12000)
    libc.so.6 => /lib/libc.so.6 (0x002e4000)
    /lib/ld-linux.so.2 (0x002c2000)

The crtl and ld-linux load addresses are consistent, but linux-gate is randomized.

Libraries are needed because the C run time initialization and termination needs to run. Granted, those could largely be optimized away since stdin, stdout, stderr, etc., etc. don't need to be initialized. Still, the crtl is how main() gets called.

Different flavors and versions of Linux have differences. The evolution of glib has had many twists and turns. Some stuff has been moved to other libraries. It's pretty much the same thing as why your local grocery store moves things around. It doesn't have much meaning.

wallyk
`two.c` could conceivably be optimized into a 0-byte (or almost 0-byte) program. But no vendor is going to build compilers that optimize for trivial programs.
larsmans
+5  A: 

What does the address given in brackets (for example, (0x002de000)) mean?

It is the (virtual) memory address where the library is loaded. Recent system can provide randomization of where libraries are loaded though, so that address might vary between invocations.

shouldn't they be loaded only at runtime?

Yes they are. ldd goes through much of the same procedure as what is done at runtime though, to be able to figure out various things.

Why does two need any libraries at all?

libc.so.6 is the standard C library (and other stuff, like the interface to the kernel) and is always linked in ny default. gcc has options to control this though, e.g. the -nostdlib flag

ld-linux.so is a the dynamic loader, and is repsonsible for loading/relocating other shared libraryis and run your application. The manpage for ld-linux.so gives you the details.

linux-gate.so.1 is a virtual library, it exists only in memory in the kernel. It's used to perform system calls to the kernel, and figures out the most efficient way to do so based on your CPU. This was probably added to linux later than your other 2.6.9 kernel machine.

I don't know what /usr/lib/libcwait.so is , but chances are you can get some info about it by doing rpm -qif /usr/lib/libcwait.so

nos