In each section the build system places different entities. The important sections are

.text – the compiled code

.data – initialized data

.bss – uninitialized data

.bss and .data

To see the difference lets look at a simple code:

1

2

3

4

5

6

7

8

9

intarr[1000];

voidmain()

{

arr[0]=1;

arr[1]=2;

....

}

If we declare a global array without initialization – the build system place it in .bss section:

readelf output:

On application loading the .bss section allocated in ram. The ELF file size:

But if we add some values to initailize the array:

1

2

3

4

5

6

7

intarr[1024]={1,2};

voidmain()

{

char*str="hello have a good day.....";

...

}

We can see that the array is now on .data section:

and the ELF size is now bigger:

means that the ELF file contains the array even if we only initialized only 2 elements

So if the same program declare the array size as 1000000 :

1

2

3

4

5

6

7

intarr[1000000]={1,2};

voidmain()

{

char*str="hello have a good day.....";

...

}

the size is now:

i.e. the ELF file is now full of zeros

Debugging Information

debugging info is placed inside the ELF file to let the debugger know the source line correspond to the machine code. The debugger load the program and use the debug info to know where to place breakpoints – It replace the machine instruction with a trap (in x86 – int 3) , this will cause the CPU to generate an exception and it replace it back after resuming

if we compile the code with debug info we will see it size get bigger:

And the sections:

Other useful tools

nm – list the symbols with addresses:

1

2

3

4

5

6

7

8

developer@:~/testapp$nm app2

0000000000601048Da1

000000000060104cDa2

0000000000601050B__bss_start

0000000000601050bcompleted.7585

0000000000601038D__data_start

0000000000601038Wdata_start

.....

objdump – display information for object file:

headers (-x)

debugging information (-g)

disassembly (-d)

disassembly with source code (-S)

and more …

1

2

3

4

5

6

7

8

9

10

11

12

13

14

# objdump -S ./app2

...

voidmain()

{

400626:55push%rbp

400627:4889e5 mov%rsp,%rbp

40062a:4883ec10sub$0x10,%rsp

char*str="hello have a good day.....";

40062e:48c745f8 f40640movq$0x4006f4,-0x8(%rbp)

400635:00

f1();

400636:b800000000mov$0x0,%eax

40063b:e887ff ff ff callq4005c7<f1>

puts(str);

addr2line – display the source code line number from known address

This is very useful if the program crashed and we wrote a fault handler to display the faulty address (program counter). We can use this tool with ELF containing debug info (the crashed program can be stripped):

1

2

developer@:~/testapp$addr2line-eapp20x400630

/home/developer/testapp/./a.c:25

strip – remove symbols and debugging information from ELF file

Before we deploy our app, we can remove all the symbols and debug info without the need to compile it again.

1

2

3

4

5

6

developer@:~/testapp$strip-oappstripped./app

developer@:~/testapp$ls-l

total44

-rw-rw-r--1developer developer290dec719:04a.c

-rwxrwxr-x1developer developer29864dec719:05app

-rwxrwxr-x1developer developer6336dec721:17appstripped

objcopy -copy and translate object files

you can use objcopy to copy content from one elf file to another, for example if you want to copy only debug information to a separate file use: